1dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/*
2dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Licensed to the Apache Software Foundation (ASF) under one or more
3dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * contributor license agreements.  See the NOTICE file distributed with
4dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * this work for additional information regarding copyright ownership.
5dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ASF licenses this file to You under the Apache License, Version 2.0
6dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (the "License"); you may not use this file except in compliance with
7dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the License.  You may obtain a copy of the License at
8dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
9dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *      http://www.apache.org/licenses/LICENSE-2.0
10dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
11dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Unless required by applicable law or agreed to in writing, software
12dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * distributed under the License is distributed on an "AS IS" BASIS,
13dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * See the License for the specific language governing permissions and
15dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * limitations under the License.
16dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
17dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpackage org.apache.commons.math.stat.descriptive.rank;
18dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
19dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.io.Serializable;
20dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport java.util.Arrays;
21dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
22dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.MathRuntimeException;
23dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.exception.util.LocalizedFormats;
24dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.stat.descriptive.AbstractUnivariateStatistic;
25dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondimport org.apache.commons.math.util.FastMath;
26dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
27dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond/**
28dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Provides percentile computation.
29dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
30dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * There are several commonly used methods for estimating percentiles (a.k.a.
31dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * quantiles) based on sample data.  For large samples, the different methods
32dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * agree closely, but when sample sizes are small, different methods will give
33dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * significantly different results.  The algorithm implemented here works as follows:
34dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <ol>
35dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>Let <code>n</code> be the length of the (sorted) array and
36dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code>0 < p <= 100</code> be the desired percentile.</li>
37dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>If <code> n = 1 </code> return the unique array element (regardless of
38dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * the value of <code>p</code>); otherwise </li>
39dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>Compute the estimated percentile position
40dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code> pos = p * (n + 1) / 100</code> and the difference, <code>d</code>
41dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * between <code>pos</code> and <code>floor(pos)</code> (i.e. the fractional
42dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * part of <code>pos</code>).  If <code>pos >= n</code> return the largest
43dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * element in the array; otherwise</li>
44dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <li>Let <code>lower</code> be the element in position
45dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code>floor(pos)</code> in the array and let <code>upper</code> be the
46dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * next element in the array.  Return <code>lower + d * (upper - lower)</code>
47dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * </li>
48dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * </ol></p>
49dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
50dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * To compute percentiles, the data must be at least partially ordered.  Input
51dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * arrays are copied and recursively partitioned using an ordering definition.
52dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * The ordering used by <code>Arrays.sort(double[])</code> is the one determined
53dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * by {@link java.lang.Double#compareTo(Double)}.  This ordering makes
54dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code>Double.NaN</code> larger than any other value (including
55dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code>Double.POSITIVE_INFINITY</code>).  Therefore, for example, the median
56dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * (50th percentile) of
57dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code>{0, 1, 2, 3, 4, Double.NaN}</code> evaluates to <code>2.5.</code></p>
58dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
59dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Since percentile estimation usually involves interpolation between array
60dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * elements, arrays containing  <code>NaN</code> or infinite values will often
61dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * result in <code>NaN<code> or infinite values returned.</p>
62dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
63dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * Since 2.2, Percentile implementation uses only selection instead of complete
64dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * sorting and caches selection algorithm state between calls to the various
65dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * {@code evaluate} methods when several percentiles are to be computed on the same data.
66dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * This greatly improves efficiency, both for single percentile and multiple
67dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * percentiles computations. However, it also induces a need to be sure the data
68dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * at one call to {@code evaluate} is the same as the data with the cached algorithm
69dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * state from the previous calls. Percentile does this by checking the array reference
70dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * itself and a checksum of its content by default. If the user already knows he calls
71dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * {@code evaluate} on an immutable array, he can save the checking time by calling the
72dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * {@code evaluate} methods that do <em>not</em>
73dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * </p>
74dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <p>
75dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <strong>Note that this implementation is not synchronized.</strong> If
76dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * multiple threads access an instance of this class concurrently, and at least
77dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * one of the threads invokes the <code>increment()</code> or
78dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * <code>clear()</code> method, it must be synchronized externally.</p>
79dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond *
80dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond * @version $Revision: 1006299 $ $Date: 2010-10-10 16:47:17 +0200 (dim. 10 oct. 2010) $
81dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond */
82dee0849a9704d532af0b550146cbafbaa6ee1d19Raymondpublic class Percentile extends AbstractUnivariateStatistic implements Serializable {
83dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
84dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Serializable version identifier */
85dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final long serialVersionUID = -8091216485095130416L;
86dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
87dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Minimum size under which we use a simple insertion sort rather than Hoare's select. */
88dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final int MIN_SELECT_SIZE = 15;
89dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
90dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Maximum number of partitioning pivots cached (each level double the number of pivots). */
91dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private static final int MAX_CACHED_LEVELS = 10;
92dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
93dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Determines what percentile is computed when evaluate() is activated
94dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * with no quantile argument */
95dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double quantile = 0.0;
96dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
97dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Cached pivots. */
98dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int[] cachedPivots;
99dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
100dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
101dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Constructs a Percentile with a default quantile
102dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * value of 50.0.
103dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
104dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public Percentile() {
105dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        this(50.0);
106dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
107dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
108dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
109dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Constructs a Percentile with the specific quantile value.
110dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p the quantile
111dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException  if p is not greater than 0 and less
112dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * than or equal to 100
113dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
114dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public Percentile(final double p) {
115dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        setQuantile(p);
116dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        cachedPivots = null;
117dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
118dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
119dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
120dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Copy constructor, creates a new {@code Percentile} identical
121dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * to the {@code original}
122dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
123dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param original the {@code Percentile} instance to copy
124dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
125dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public Percentile(Percentile original) {
126dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        copy(original, this);
127dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
128dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
129dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
130dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
131dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setData(final double[] values) {
132dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (values == null) {
133dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedPivots = null;
134dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
135dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedPivots = new int[(0x1 << MAX_CACHED_LEVELS) - 1];
136dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            Arrays.fill(cachedPivots, -1);
137dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
138dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super.setData(values);
139dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
140dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
141dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** {@inheritDoc} */
142dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
143dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setData(final double[] values, final int begin, final int length) {
144dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (values == null) {
145dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedPivots = null;
146dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
147dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            cachedPivots = new int[(0x1 << MAX_CACHED_LEVELS) - 1];
148dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            Arrays.fill(cachedPivots, -1);
149dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
150dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        super.setData(values, begin, length);
151dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
152dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
153dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
154dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the result of evaluating the statistic over the stored data.
155dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
156dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * The stored array is the one which was set by previous calls to
157dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </p>
158dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p the percentile value to compute
159dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the value of the statistic applied to the stored data
160dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
161dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double evaluate(final double p) {
162dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return evaluate(getDataRef(), p);
163dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
164dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
165dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
166dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns an estimate of the <code>p</code>th percentile of the values
167dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * in the <code>values</code> array.
168dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
169dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Calls to this method do not modify the internal <code>quantile</code>
170dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * state of this statistic.</p>
171dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
172dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <ul>
173dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Returns <code>Double.NaN</code> if <code>values</code> has length
174dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>0</code></li>
175dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Returns (for any value of <code>p</code>) <code>values[0]</code>
176dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  if <code>values</code> has length <code>1</code></li>
177dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
178dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * is null or p is not a valid quantile value (p must be greater than 0
179dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * and less than or equal to 100) </li>
180dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </ul></p>
181dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
182dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * See {@link Percentile} for a description of the percentile estimation
183dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * algorithm used.</p>
184dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
185dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param values input array of values
186dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p the percentile value to compute
187dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the percentile value or Double.NaN if the array is empty
188dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if <code>values</code> is null
189dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *     or p is invalid
190dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
191dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double evaluate(final double[] values, final double p) {
192dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        test(values, 0, 0);
193dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return evaluate(values, 0, values.length, p);
194dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
195dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
196dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
197dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns an estimate of the <code>quantile</code>th percentile of the
198dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * designated values in the <code>values</code> array.  The quantile
199dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * estimated is determined by the <code>quantile</code> property.
200dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
201dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <ul>
202dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Returns <code>Double.NaN</code> if <code>length = 0</code></li>
203dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Returns (for any value of <code>quantile</code>)
204dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>values[begin]</code> if <code>length = 1 </code></li>
205dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
206dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * is null,  or <code>start</code> or <code>length</code>
207dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * is invalid</li>
208dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </ul></p>
209dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
210dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * See {@link Percentile} for a description of the percentile estimation
211dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * algorithm used.</p>
212dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
213dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param values the input array
214dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param start index of the first array element to include
215dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param length the number of elements to include
216dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the percentile value
217dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if the parameters are not valid
218dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
219dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
220dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
221dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double evaluate( final double[] values, final int start, final int length) {
222dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return evaluate(values, start, length, quantile);
223dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
224dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
225dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     /**
226dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns an estimate of the <code>p</code>th percentile of the values
227dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * in the <code>values</code> array, starting with the element in (0-based)
228dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * position <code>begin</code> in the array and including <code>length</code>
229dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * values.
230dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
231dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Calls to this method do not modify the internal <code>quantile</code>
232dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * state of this statistic.</p>
233dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
234dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <ul>
235dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Returns <code>Double.NaN</code> if <code>length = 0</code></li>
236dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Returns (for any value of <code>p</code>) <code>values[begin]</code>
237dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  if <code>length = 1 </code></li>
238dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
239dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *  is null , <code>begin</code> or <code>length</code> is invalid, or
240dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <code>p</code> is not a valid quantile value (p must be greater than 0
241dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * and less than or equal to 100)</li>
242dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </ul></p>
243dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
244dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * See {@link Percentile} for a description of the percentile estimation
245dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * algorithm used.</p>
246dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
247dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param values array of input values
248dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p  the percentile to compute
249dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param begin  the first (0-based) element to include in the computation
250dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param length  the number of array elements to include
251dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return  the percentile value
252dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException if the parameters are not valid or the
253dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * input array is null
254dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
255dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double evaluate(final double[] values, final int begin,
256dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int length, final double p) {
257dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
258dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        test(values, begin, length);
259dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
260dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if ((p > 100) || (p <= 0)) {
261dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
262dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                  LocalizedFormats.OUT_OF_BOUNDS_QUANTILE_VALUE, p);
263dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
264dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (length == 0) {
265dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return Double.NaN;
266dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
267dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (length == 1) {
268dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return values[begin]; // always return single value for n = 1
269dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
270dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double n = length;
271dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double pos = p * (n + 1) / 100;
272dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double fpos = FastMath.floor(pos);
273dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int intPos = (int) fpos;
274dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double dif = pos - fpos;
275dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double[] work;
276dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int[] pivotsHeap;
277dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (values == getDataRef()) {
278dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            work = getDataRef();
279dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pivotsHeap = cachedPivots;
280dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
281dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            work = new double[length];
282dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(values, begin, work, 0, length);
283dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            pivotsHeap = new int[(0x1 << MAX_CACHED_LEVELS) - 1];
284dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            Arrays.fill(pivotsHeap, -1);
285dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
286dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
287dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (pos < 1) {
288dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return select(work, pivotsHeap, 0);
289dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
290dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (pos >= n) {
291dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            return select(work, pivotsHeap, length - 1);
292dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
293dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double lower = select(work, pivotsHeap, intPos - 1);
294dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        double upper = select(work, pivotsHeap, intPos);
295dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return lower + dif * (upper - lower);
296dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
297dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
298dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
299dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Select the k<sup>th</sup> smallest element from work array
300dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param work work array (will be reorganized during the call)
301dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param pivotsHeap set of pivot index corresponding to elements that
302dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * are already at their sorted location, stored as an implicit heap
303dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * (i.e. a sorted binary tree stored in a flat array, where the
304dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * children of a node at index n are at indices 2n+1 for the left
305dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * child and 2n+2 for the right child, with 0-based indices)
306dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param k index of the desired element
307dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return k<sup>th</sup> smallest element
308dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
309dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private double select(final double[] work, final int[] pivotsHeap, final int k) {
310dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
311dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int begin = 0;
312dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int end   = work.length;
313dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int node  = 0;
314dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
315dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        while (end - begin > MIN_SELECT_SIZE) {
316dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
317dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final int pivot;
318dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if ((node < pivotsHeap.length) && (pivotsHeap[node] >= 0)) {
319dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // the pivot has already been found in a previous call
320dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // and the array has already been partitioned around it
321dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                pivot = pivotsHeap[node];
322dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } else {
323dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // select a pivot and partition work array around it
324dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                pivot = partition(work, begin, end, medianOf3(work, begin, end));
325dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                if (node < pivotsHeap.length) {
326dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                    pivotsHeap[node] =  pivot;
327dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                }
328dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
329dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
330dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (k == pivot) {
331dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // the pivot was exactly the element we wanted
332dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return work[k];
333dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } else if (k < pivot) {
334dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // the element is in the left partition
335dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                end  = pivot;
336dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                node = Math.min(2 * node + 1, pivotsHeap.length); // the min is here to avoid integer overflow
337dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } else {
338dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                // the element is in the right partition
339dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                begin = pivot + 1;
340dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                node  = Math.min(2 * node + 2, pivotsHeap.length); // the min is here to avoid integer overflow
341dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
342dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
343dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
344dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
345dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // the element is somewhere in the small sub-array
346dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        // sort the sub-array using insertion sort
347dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        insertionSort(work, begin, end);
348dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return work[k];
349dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
350dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
351dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
352dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /** Select a pivot index as the median of three
353dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param work data array
354dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param begin index of the first element of the slice
355dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param end index after the last element of the slice
356dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return the index of the median element chosen between the
357dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * first, the middle and the last element of the array slice
358dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
359dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    int medianOf3(final double[] work, final int begin, final int end) {
360dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
361dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int inclusiveEnd = end - 1;
362dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final int    middle    = begin + (inclusiveEnd - begin) / 2;
363dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double wBegin    = work[begin];
364dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double wMiddle   = work[middle];
365dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double wEnd      = work[inclusiveEnd];
366dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
367dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (wBegin < wMiddle) {
368dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (wMiddle < wEnd) {
369dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return middle;
370dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } else {
371dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return (wBegin < wEnd) ? inclusiveEnd : begin;
372dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
373dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        } else {
374dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (wBegin < wEnd) {
375dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return begin;
376dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            } else {
377dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                return (wMiddle < wEnd) ? inclusiveEnd : middle;
378dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
379dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
380dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
381dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
382dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
383dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
384dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Partition an array slice around a pivot
385dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>
386dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Partitioning exchanges array elements such that all elements
387dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * smaller than pivot are before it and all elements larger than
388dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * pivot are after it
389dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * </p>
390dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param work data array
391dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param begin index of the first element of the slice
392dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param end index after the last element of the slice
393dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param pivot initial index of the pivot
394dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return index of the pivot after partition
395dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
396dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private int partition(final double[] work, final int begin, final int end, final int pivot) {
397dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
398dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        final double value = work[pivot];
399dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        work[pivot] = work[begin];
400dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
401dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int i = begin + 1;
402dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        int j = end - 1;
403dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        while (i < j) {
404dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            while ((i < j) && (work[j] >= value)) {
405dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                --j;
406dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
407dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            while ((i < j) && (work[i] <= value)) {
408dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                ++i;
409dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
410dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
411dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            if (i < j) {
412dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                final double tmp = work[i];
413dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                work[i++] = work[j];
414dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                work[j--] = tmp;
415dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
416dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
417dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
418dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if ((i >= end) || (work[i] > value)) {
419dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            --i;
420dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
421dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        work[begin] = work[i];
422dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        work[i]     = value;
423dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return i;
424dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
425dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
426dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
427dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
428dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Sort in place a (small) array slice using insertion sort
429dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param work array to sort
430dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param begin index of the first element of the slice to sort
431dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param end index after the last element of the slice to sort
432dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
433dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    private void insertionSort(final double[] work, final int begin, final int end) {
434dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        for (int j = begin + 1; j < end; j++) {
435dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            final double saved = work[j];
436dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            int i = j - 1;
437dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            while ((i >= begin) && (saved < work[i])) {
438dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                work[i + 1] = work[i];
439dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                i--;
440dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            }
441dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            work[i + 1] = saved;
442dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
443dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
444dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
445dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
446dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Returns the value of the quantile field (determines what percentile is
447dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * computed when evaluate() is called with no quantile argument).
448dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
449dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @return quantile
450dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
451dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public double getQuantile() {
452dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return quantile;
453dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
454dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
455dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
456dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Sets the value of the quantile field (determines what percentile is
457dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * computed when evaluate() is called with no quantile argument).
458dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
459dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param p a value between 0 < p <= 100
460dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws IllegalArgumentException  if p is not greater than 0 and less
461dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * than or equal to 100
462dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
463dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public void setQuantile(final double p) {
464dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (p <= 0 || p > 100) {
465dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            throw MathRuntimeException.createIllegalArgumentException(
466dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond                  LocalizedFormats.OUT_OF_BOUNDS_QUANTILE_VALUE, p);
467dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
468dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        quantile = p;
469dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
470dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
471dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
472dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * {@inheritDoc}
473dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
474dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    @Override
475dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public Percentile copy() {
476dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        Percentile result = new Percentile();
477dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        copy(this, result);
478dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        return result;
479dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
480dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
481dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    /**
482dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * Copies source to dest.
483dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * <p>Neither source nor dest can be null.</p>
484dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     *
485dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param source Percentile to copy
486dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @param dest Percentile to copy to
487dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     * @throws NullPointerException if either source or dest is null
488dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond     */
489dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    public static void copy(Percentile source, Percentile dest) {
490dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        dest.setData(source.getDataRef());
491dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        if (source.cachedPivots != null) {
492dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond            System.arraycopy(source.cachedPivots, 0, dest.cachedPivots, 0, source.cachedPivots.length);
493dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        }
494dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond        dest.quantile = source.quantile;
495dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond    }
496dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond
497dee0849a9704d532af0b550146cbafbaa6ee1d19Raymond}
498