1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.stat.descriptive.rank; 23 24 import java.io.Serializable; 25 26 import org.hipparchus.exception.MathIllegalArgumentException; 27 import org.hipparchus.exception.NullArgumentException; 28 import org.hipparchus.stat.descriptive.AbstractUnivariateStatistic; 29 import org.hipparchus.stat.descriptive.rank.Percentile.EstimationType; 30 import org.hipparchus.stat.ranking.NaNStrategy; 31 import org.hipparchus.util.KthSelector; 32 33 34 /** 35 * Returns the median of the available values. This is the same as the 50th percentile. 36 * See {@link Percentile} for a description of the algorithm used. 37 * <p> 38 * <strong>Note that this implementation is not synchronized.</strong> If 39 * multiple threads access an instance of this class concurrently, and at least 40 * one of the threads invokes the <code>increment()</code> or 41 * <code>clear()</code> method, it must be synchronized externally. 42 */ 43 public class Median extends AbstractUnivariateStatistic implements Serializable { 44 45 /** Serializable version identifier */ 46 private static final long serialVersionUID = 20150412L; 47 48 /** Fixed quantile. */ 49 private static final double FIXED_QUANTILE_50 = 50.0; 50 51 /** The percentile impl to calculate the median. */ 52 private final Percentile percentile; 53 54 /** 55 * Default constructor. 56 */ 57 public Median() { 58 percentile = new Percentile(FIXED_QUANTILE_50); 59 } 60 61 /** 62 * Constructs a Median with the specific {@link EstimationType}, 63 * {@link NaNStrategy} and {@link KthSelector}. 64 * 65 * @param estimationType one of the percentile {@link EstimationType estimation types} 66 * @param nanStrategy one of {@link NaNStrategy} to handle with NaNs 67 * @param kthSelector {@link KthSelector} to use for pivoting during search 68 * @throws MathIllegalArgumentException if p is not within (0,100] 69 * @throws NullArgumentException if type or NaNStrategy passed is null 70 */ 71 private Median(final EstimationType estimationType, final NaNStrategy nanStrategy, 72 final KthSelector kthSelector) 73 throws MathIllegalArgumentException { 74 75 percentile = new Percentile(FIXED_QUANTILE_50, estimationType, 76 nanStrategy, kthSelector); 77 } 78 79 /** 80 * Copy constructor, creates a new {@code Median} identical 81 * to the {@code original} 82 * 83 * @param original the {@code Median} instance to copy 84 * @throws NullArgumentException if original is null 85 */ 86 Median(Median original) throws NullArgumentException { 87 super(original); 88 this.percentile = original.percentile.copy(); 89 } 90 91 /** {@inheritDoc} */ 92 @Override 93 public double evaluate(double[] values, int begin, int length) 94 throws MathIllegalArgumentException { 95 return percentile.evaluate(values, begin, length); 96 } 97 98 /** {@inheritDoc} */ 99 @Override 100 public Median copy() { 101 return new Median(this); 102 } 103 104 /** 105 * Get the estimation {@link EstimationType type} used for computation. 106 * 107 * @return the {@code estimationType} set 108 */ 109 public EstimationType getEstimationType() { 110 return percentile.getEstimationType(); 111 } 112 113 /** 114 * Build a new instance similar to the current one except for the 115 * {@link EstimationType estimation type}. 116 * 117 * @param newEstimationType estimation type for the new instance 118 * @return a new instance, with changed estimation type 119 * @throws NullArgumentException when newEstimationType is null 120 */ 121 public Median withEstimationType(final EstimationType newEstimationType) { 122 return new Median(newEstimationType, 123 percentile.getNaNStrategy(), 124 percentile.getKthSelector()); 125 } 126 127 /** 128 * Get the {@link NaNStrategy NaN Handling} strategy used for computation. 129 * @return {@code NaN Handling} strategy set during construction 130 */ 131 public NaNStrategy getNaNStrategy() { 132 return percentile.getNaNStrategy(); 133 } 134 135 /** 136 * Build a new instance similar to the current one except for the 137 * {@link NaNStrategy NaN handling} strategy. 138 * 139 * @param newNaNStrategy NaN strategy for the new instance 140 * @return a new instance, with changed NaN handling strategy 141 * @throws NullArgumentException when newNaNStrategy is null 142 */ 143 public Median withNaNStrategy(final NaNStrategy newNaNStrategy) { 144 return new Median(percentile.getEstimationType(), 145 newNaNStrategy, 146 percentile.getKthSelector()); 147 } 148 149 /** 150 * Get the {@link KthSelector kthSelector} used for computation. 151 * @return the {@code kthSelector} set 152 */ 153 public KthSelector getKthSelector() { 154 return percentile.getKthSelector(); 155 } 156 157 /** 158 * Build a new instance similar to the current one except for the 159 * {@link KthSelector kthSelector} instance specifically set. 160 * 161 * @param newKthSelector KthSelector for the new instance 162 * @return a new instance, with changed KthSelector 163 * @throws NullArgumentException when newKthSelector is null 164 */ 165 public Median withKthSelector(final KthSelector newKthSelector) { 166 return new Median(percentile.getEstimationType(), 167 percentile.getNaNStrategy(), 168 newKthSelector); 169 } 170 171 }