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 }