    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.math.stat;
    018
    019    import org.apache.commons.math.MathRuntimeException;
    020    import org.apache.commons.math.exception.util.LocalizedFormats;
    021    import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
    022    import org.apache.commons.math.stat.descriptive.UnivariateStatistic;
    023    import org.apache.commons.math.stat.descriptive.moment.GeometricMean;
    024    import org.apache.commons.math.stat.descriptive.moment.Mean;
    025    import org.apache.commons.math.stat.descriptive.moment.Variance;
    026    import org.apache.commons.math.stat.descriptive.rank.Max;
    027    import org.apache.commons.math.stat.descriptive.rank.Min;
    028    import org.apache.commons.math.stat.descriptive.rank.Percentile;
    029    import org.apache.commons.math.stat.descriptive.summary.Product;
    030    import org.apache.commons.math.stat.descriptive.summary.Sum;
    031    import org.apache.commons.math.stat.descriptive.summary.SumOfLogs;
    032    import org.apache.commons.math.stat.descriptive.summary.SumOfSquares;
    033
    034    /**
    035     * StatUtils provides static methods for computing statistics based on data
    036     * stored in double[] arrays.
    037     *
    038     * @version $Revision: 1073276 $ $Date: 2011-02-22 10:34:52 +0100 (mar. 22 f??vr. 2011) $
    039     */
    040    public final class StatUtils {
    041
    042        /** sum */
    043        private static final UnivariateStatistic SUM = new Sum();
    044
    045        /** sumSq */
    046        private static final UnivariateStatistic SUM_OF_SQUARES = new SumOfSquares();
    047
    048        /** prod */
    049        private static final UnivariateStatistic PRODUCT = new Product();
    050
    051        /** sumLog */
    052        private static final UnivariateStatistic SUM_OF_LOGS = new SumOfLogs();
    053
    054        /** min */
    055        private static final UnivariateStatistic MIN = new Min();
    056
    057        /** max */
    058        private static final UnivariateStatistic MAX = new Max();
    059
    060        /** mean */
    061        private static final UnivariateStatistic MEAN = new Mean();
    062
    063        /** variance */
    064        private static final Variance VARIANCE = new Variance();
    065
    066        /** percentile */
    067        private static final Percentile PERCENTILE = new Percentile();
    068
    069        /** geometric mean */
    070        private static final GeometricMean GEOMETRIC_MEAN = new GeometricMean();
    071
    072        /**
    073         * Private Constructor
    074         */
    075        private StatUtils() {
    076        }
    077
    078        /**
    079         * Returns the sum of the values in the input array, or
    080         * <code>Double.NaN</code> if the array is empty.
    081         * <p>
    082         * Throws <code>IllegalArgumentException</code> if the input array
    083         * is null.</p>
    084         *
    085         * @param values  array of values to sum
    086         * @return the sum of the values or <code>Double.NaN</code> if the array
    087         * is empty
    088         * @throws IllegalArgumentException if the array is null
    089         */
    090        public static double sum(final double[] values) {
    091            return SUM.evaluate(values);
    092        }
    093
    094        /**
    095         * Returns the sum of the entries in the specified portion of
    096         * the input array, or <code>Double.NaN</code> if the designated subarray
    097         * is empty.
    098         * <p>
    099         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    100         *
    101         * @param values the input array
    102         * @param begin index of the first array element to include
    103         * @param length the number of elements to include
    104         * @return the sum of the values or Double.NaN if length = 0
    105         * @throws IllegalArgumentException if the array is null or the array index
    106         *  parameters are not valid
    107         */
    108        public static double sum(final double[] values, final int begin,
    109                final int length) {
    110            return SUM.evaluate(values, begin, length);
    111        }
    112
    113        /**
    114         * Returns the sum of the squares of the entries in the input array, or
    115         * <code>Double.NaN</code> if the array is empty.
    116         * <p>
    117         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    118         *
    119         * @param values  input array
    120         * @return the sum of the squared values or <code>Double.NaN</code> if the
    121         * array is empty
    122         * @throws IllegalArgumentException if the array is null
    123         */
    124        public static double sumSq(final double[] values) {
    125            return SUM_OF_SQUARES.evaluate(values);
    126        }
    127
    128        /**
    129         * Returns the sum of the squares of the entries in the specified portion of
    130         * the input array, or <code>Double.NaN</code> if the designated subarray
    131         * is empty.
    132         * <p>
    133         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    134         *
    135         * @param values the input array
    136         * @param begin index of the first array element to include
    137         * @param length the number of elements to include
    138         * @return the sum of the squares of the values or Double.NaN if length = 0
    139         * @throws IllegalArgumentException if the array is null or the array index
    140         * parameters are not valid
    141         */
    142        public static double sumSq(final double[] values, final int begin,
    143                final int length) {
    144            return SUM_OF_SQUARES.evaluate(values, begin, length);
    145        }
    146
    147        /**
    148         * Returns the product of the entries in the input array, or
    149         * <code>Double.NaN</code> if the array is empty.
    150         * <p>
    151         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    152         *
    153         * @param values the input array
    154         * @return the product of the values or Double.NaN if the array is empty
    155         * @throws IllegalArgumentException if the array is null
    156         */
    157        public static double product(final double[] values) {
    158            return PRODUCT.evaluate(values);
    159        }
    160
    161        /**
    162         * Returns the product of the entries in the specified portion of
    163         * the input array, or <code>Double.NaN</code> if the designated subarray
    164         * is empty.
    165         * <p>
    166         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    167         *
    168         * @param values the input array
    169         * @param begin index of the first array element to include
    170         * @param length the number of elements to include
    171         * @return the product of the values or Double.NaN if length = 0
    172         * @throws IllegalArgumentException if the array is null or the array index
    173         * parameters are not valid
    174         */
    175        public static double product(final double[] values, final int begin,
    176                final int length) {
    177            return PRODUCT.evaluate(values, begin, length);
    178        }
    179
    180        /**
    181         * Returns the sum of the natural logs of the entries in the input array, or
    182         * <code>Double.NaN</code> if the array is empty.
    183         * <p>
    184         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    185         * <p>
    186         * See {@link org.apache.commons.math.stat.descriptive.summary.SumOfLogs}.
    187         * </p>
    188         *
    189         * @param values the input array
    190         * @return the sum of the natural logs of the values or Double.NaN if
    191         * the array is empty
    192         * @throws IllegalArgumentException if the array is null
    193         */
    194        public static double sumLog(final double[] values) {
    195            return SUM_OF_LOGS.evaluate(values);
    196        }
    197
    198        /**
    199         * Returns the sum of the natural logs of the entries in the specified portion of
    200         * the input array, or <code>Double.NaN</code> if the designated subarray
    201         * is empty.
    202         * <p>
    203         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    204         * <p>
    205         * See {@link org.apache.commons.math.stat.descriptive.summary.SumOfLogs}.
    206         * </p>
    207         *
    208         * @param values the input array
    209         * @param begin index of the first array element to include
    210         * @param length the number of elements to include
    211         * @return the sum of the natural logs of the values or Double.NaN if
    212         * length = 0
    213         * @throws IllegalArgumentException if the array is null or the array index
    214         * parameters are not valid
    215         */
    216        public static double sumLog(final double[] values, final int begin,
    217                final int length) {
    218            return SUM_OF_LOGS.evaluate(values, begin, length);
    219        }
    220
    221        /**
    222         * Returns the arithmetic mean of the entries in the input array, or
    223         * <code>Double.NaN</code> if the array is empty.
    224         * <p>
    225         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    226         * <p>
    227         * See {@link org.apache.commons.math.stat.descriptive.moment.Mean} for
    228         * details on the computing algorithm.</p>
    229         *
    230         * @param values the input array
    231         * @return the mean of the values or Double.NaN if the array is empty
    232         * @throws IllegalArgumentException if the array is null
    233         */
    234        public static double mean(final double[] values) {
    235            return MEAN.evaluate(values);
    236        }
    237
    238        /**
    239         * Returns the arithmetic mean of the entries in the specified portion of
    240         * the input array, or <code>Double.NaN</code> if the designated subarray
    241         * is empty.
    242         * <p>
    243         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    244         * <p>
    245         * See {@link org.apache.commons.math.stat.descriptive.moment.Mean} for
    246         * details on the computing algorithm.</p>
    247         *
    248         * @param values the input array
    249         * @param begin index of the first array element to include
    250         * @param length the number of elements to include
    251         * @return the mean of the values or Double.NaN if length = 0
    252         * @throws IllegalArgumentException if the array is null or the array index
    253         * parameters are not valid
    254         */
    255        public static double mean(final double[] values, final int begin,
    256                final int length) {
    257            return MEAN.evaluate(values, begin, length);
    258        }
    259
    260        /**
    261         * Returns the geometric mean of the entries in the input array, or
    262         * <code>Double.NaN</code> if the array is empty.
    263         * <p>
    264         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    265         * <p>
    266         * See {@link org.apache.commons.math.stat.descriptive.moment.GeometricMean}
    267         * for details on the computing algorithm.</p>
    268         *
    269         * @param values the input array
    270         * @return the geometric mean of the values or Double.NaN if the array is empty
    271         * @throws IllegalArgumentException if the array is null
    272         */
    273        public static double geometricMean(final double[] values) {
    274            return GEOMETRIC_MEAN.evaluate(values);
    275        }
    276
    277        /**
    278         * Returns the geometric mean of the entries in the specified portion of
    279         * the input array, or <code>Double.NaN</code> if the designated subarray
    280         * is empty.
    281         * <p>
    282         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    283         * <p>
    284         * See {@link org.apache.commons.math.stat.descriptive.moment.GeometricMean}
    285         * for details on the computing algorithm.</p>
    286         *
    287         * @param values the input array
    288         * @param begin index of the first array element to include
    289         * @param length the number of elements to include
    290         * @return the geometric mean of the values or Double.NaN if length = 0
    291         * @throws IllegalArgumentException if the array is null or the array index
    292         * parameters are not valid
    293         */
    294        public static double geometricMean(final double[] values, final int begin,
    295                final int length) {
    296            return GEOMETRIC_MEAN.evaluate(values, begin, length);
    297        }
    298
    299
    300        /**
    301         * Returns the variance of the entries in the input array, or
    302         * <code>Double.NaN</code> if the array is empty.
    303         * <p>
    304         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
    305         * details on the computing algorithm.</p>
    306         * <p>
    307         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
    308         * <p>
    309         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    310         *
    311         * @param values the input array
    312         * @return the variance of the values or Double.NaN if the array is empty
    313         * @throws IllegalArgumentException if the array is null
    314         */
    315        public static double variance(final double[] values) {
    316            return VARIANCE.evaluate(values);
    317        }
    318
    319        /**
    320         * Returns the variance of the entries in the specified portion of
    321         * the input array, or <code>Double.NaN</code> if the designated subarray
    322         * is empty.
    323         * <p>
    324         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
    325         * details on the computing algorithm.</p>
    326         * <p>
    327         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
    328         * <p>
    329         * Throws <code>IllegalArgumentException</code> if the array is null or the
    330         * array index parameters are not valid.</p>
    331         *
    332         * @param values the input array
    333         * @param begin index of the first array element to include
    334         * @param length the number of elements to include
    335         * @return the variance of the values or Double.NaN if length = 0
    336         * @throws IllegalArgumentException if the array is null or the array index
    337         *  parameters are not valid
    338         */
    339        public static double variance(final double[] values, final int begin,
    340                final int length) {
    341            return VARIANCE.evaluate(values, begin, length);
    342        }
    343
    344        /**
    345         * Returns the variance of the entries in the specified portion of
    346         * the input array, using the precomputed mean value.  Returns
    347         * <code>Double.NaN</code> if the designated subarray is empty.
    348         * <p>
    349         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
    350         * details on the computing algorithm.</p>
    351         * <p>
    352         * The formula used assumes that the supplied mean value is the arithmetic
    353         * mean of the sample data, not a known population parameter.  This method
    354         * is supplied only to save computation when the mean has already been
    355         * computed.</p>
    356         * <p>
    357         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
    358         * <p>
    359         * Throws <code>IllegalArgumentException</code> if the array is null or the
    360         * array index parameters are not valid.</p>
    361         *
    362         * @param values the input array
    363         * @param mean the precomputed mean value
    364         * @param begin index of the first array element to include
    365         * @param length the number of elements to include
    366         * @return the variance of the values or Double.NaN if length = 0
    367         * @throws IllegalArgumentException if the array is null or the array index
    368         *  parameters are not valid
    369         */
    370        public static double variance(final double[] values, final double mean,
    371                final int begin, final int length) {
    372            return VARIANCE.evaluate(values, mean, begin, length);
    373        }
    374
    375        /**
    376         * Returns the variance of the entries in the input array, using the
    377         * precomputed mean value.  Returns <code>Double.NaN</code> if the array
    378         * is empty.
    379         * <p>
    380         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
    381         * details on the computing algorithm.</p>
    382         * <p>
    383         * The formula used assumes that the supplied mean value is the arithmetic
    384         * mean of the sample data, not a known population parameter.  This method
    385         * is supplied only to save computation when the mean has already been
    386         * computed.</p>
    387         * <p>
    388         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
    389         * <p>
    390         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    391         *
    392         * @param values the input array
    393         * @param mean the precomputed mean value
    394         * @return the variance of the values or Double.NaN if the array is empty
    395         * @throws IllegalArgumentException if the array is null
    396         */
    397        public static double variance(final double[] values, final double mean) {
    398            return VARIANCE.evaluate(values, mean);
    399        }
    400
    401        /**
    402         * Returns the maximum of the entries in the input array, or
    403         * <code>Double.NaN</code> if the array is empty.
    404         * <p>
    405         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    406         * <p>
    407         * <ul>
    408         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
    409         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
    410         * <li>If any of the values equals <code>Double.POSITIVE_INFINITY</code>,
    411         * the result is <code>Double.POSITIVE_INFINITY.</code></li>
    412         * </ul></p>
    413         *
    414         * @param values the input array
    415         * @return the maximum of the values or Double.NaN if the array is empty
    416         * @throws IllegalArgumentException if the array is null
    417         */
    418        public static double max(final double[] values) {
    419            return MAX.evaluate(values);
    420        }
    421
    422        /**
    423         * Returns the maximum of the entries in the specified portion of
    424         * the input array, or <code>Double.NaN</code> if the designated subarray
    425         * is empty.
    426         * <p>
    427         * Throws <code>IllegalArgumentException</code> if the array is null or
    428         * the array index parameters are not valid.</p>
    429         * <p>
    430         * <ul>
    431         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
    432         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
    433         * <li>If any of the values equals <code>Double.POSITIVE_INFINITY</code>,
    434         * the result is <code>Double.POSITIVE_INFINITY.</code></li>
    435         * </ul></p>
    436         *
    437         * @param values the input array
    438         * @param begin index of the first array element to include
    439         * @param length the number of elements to include
    440         * @return the maximum of the values or Double.NaN if length = 0
    441         * @throws IllegalArgumentException if the array is null or the array index
    442         * parameters are not valid
    443         */
    444        public static double max(final double[] values, final int begin,
    445                final int length) {
    446            return MAX.evaluate(values, begin, length);
    447        }
    448
    449         /**
    450         * Returns the minimum of the entries in the input array, or
    451         * <code>Double.NaN</code> if the array is empty.
    452         * <p>
    453         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
    454         * <p>
    455         * <ul>
    456         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
    457         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
    458         * <li>If any of the values equals <code>Double.NEGATIVE_INFINITY</code>,
    459         * the result is <code>Double.NEGATIVE_INFINITY.</code></li>
    460         * </ul> </p>
    461         *
    462         * @param values the input array
    463         * @return the minimum of the values or Double.NaN if the array is empty
    464         * @throws IllegalArgumentException if the array is null
    465         */
    466        public static double min(final double[] values) {
    467            return MIN.evaluate(values);
    468        }
    469
    470         /**
    471         * Returns the minimum of the entries in the specified portion of
    472         * the input array, or <code>Double.NaN</code> if the designated subarray
    473         * is empty.
    474         * <p>
    475         * Throws <code>IllegalArgumentException</code> if the array is null or
    476         * the array index parameters are not valid.</p>
    477         * <p>
    478         * <ul>
    479         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
    480         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
    481         * <li>If any of the values equals <code>Double.NEGATIVE_INFINITY</code>,
    482         * the result is <code>Double.NEGATIVE_INFINITY.</code></li>
    483         * </ul></p>
    484         *
    485         * @param values the input array
    486         * @param begin index of the first array element to include
    487         * @param length the number of elements to include
    488         * @return the minimum of the values or Double.NaN if length = 0
    489         * @throws IllegalArgumentException if the array is null or the array index
    490         * parameters are not valid
    491         */
    492        public static double min(final double[] values, final int begin,
    493                final int length) {
    494            return MIN.evaluate(values, begin, length);
    495        }
    496
    497        /**
    498         * Returns an estimate of the <code>p</code>th percentile of the values
    499         * in the <code>values</code> array.
    500         * <p>
    501         * <ul>
    502         * <li>Returns <code>Double.NaN</code> if <code>values</code> has length
    503         * <code>0</code></li></p>
    504         * <li>Returns (for any value of <code>p</code>) <code>values[0]</code>
    505         *  if <code>values</code> has length <code>1</code></li>
    506         * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
    507         * is null  or p is not a valid quantile value (p must be greater than 0
    508         * and less than or equal to 100)</li>
    509         * </ul></p>
    510         * <p>
    511         * See {@link org.apache.commons.math.stat.descriptive.rank.Percentile} for
    512         * a description of the percentile estimation algorithm used.</p>
    513         *
    514         * @param values input array of values
    515         * @param p the percentile value to compute
    516         * @return the percentile value or Double.NaN if the array is empty
    517         * @throws IllegalArgumentException if <code>values</code> is null
    518         * or p is invalid
    519         */
    520        public static double percentile(final double[] values, final double p) {
    521                return PERCENTILE.evaluate(values,p);
    522        }
    523
    524         /**
    525         * Returns an estimate of the <code>p</code>th percentile of the values
    526         * in the <code>values</code> array, starting with the element in (0-based)
    527         * position <code>begin</code> in the array and including <code>length</code>
    528         * values.
    529         * <p>
    530         * <ul>
    531         * <li>Returns <code>Double.NaN</code> if <code>length = 0</code></li>
    532         * <li>Returns (for any value of <code>p</code>) <code>values[begin]</code>
    533         *  if <code>length = 1 </code></li>
    534         * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
    535         *  is null , <code>begin</code> or <code>length</code> is invalid, or
    536         * <code>p</code> is not a valid quantile value (p must be greater than 0
    537         * and less than or equal to 100)</li>
    538         * </ul></p>
    539         * <p>
    540          * See {@link org.apache.commons.math.stat.descriptive.rank.Percentile} for
    541          * a description of the percentile estimation algorithm used.</p>
    542         *
    543         * @param values array of input values
    544         * @param p  the percentile to compute
    545         * @param begin  the first (0-based) element to include in the computation
    546         * @param length  the number of array elements to include
    547         * @return  the percentile value
    548         * @throws IllegalArgumentException if the parameters are not valid or the
    549         * input array is null
    550         */
    551        public static double percentile(final double[] values, final int begin,
    552                final int length, final double p) {
    553            return PERCENTILE.evaluate(values, begin, length, p);
    554        }
    555
    556        /**
    557         * Returns the sum of the (signed) differences between corresponding elements of the
    558         * input arrays -- i.e., sum(sample1[i] - sample2[i]).
    559         *
    560         * @param sample1  the first array
    561         * @param sample2  the second array
    562         * @return sum of paired differences
    563         * @throws IllegalArgumentException if the arrays do not have the same
    564         * (positive) length
    565         */
    566        public static double sumDifference(final double[] sample1, final double[] sample2)
    567            throws IllegalArgumentException {
    568            int n = sample1.length;
    569            if (n  != sample2.length) {
    570                throw MathRuntimeException.createIllegalArgumentException(
    571                      LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, n, sample2.length);
    572            }
    573            if (n < 1) {
    574                throw MathRuntimeException.createIllegalArgumentException(
    575                      LocalizedFormats.INSUFFICIENT_DIMENSION, sample2.length, 1);
    576            }
    577            double result = 0;
    578            for (int i = 0; i < n; i++) {
    579                result += sample1[i] - sample2[i];
    580            }
    581            return result;
    582        }
    583
    584        /**
    585         * Returns the mean of the (signed) differences between corresponding elements of the
    586         * input arrays -- i.e., sum(sample1[i] - sample2[i]) / sample1.length.
    587         *
    588         * @param sample1  the first array
    589         * @param sample2  the second array
    590         * @return mean of paired differences
    591         * @throws IllegalArgumentException if the arrays do not have the same
    592         * (positive) length
    593         */
    594        public static double meanDifference(final double[] sample1, final double[] sample2)
    595        throws IllegalArgumentException {
    596            return sumDifference(sample1, sample2) / sample1.length;
    597        }
    598
    599        /**
    600         * Returns the variance of the (signed) differences between corresponding elements of the
    601         * input arrays -- i.e., var(sample1[i] - sample2[i]).
    602         *
    603         * @param sample1  the first array
    604         * @param sample2  the second array
    605         * @param meanDifference   the mean difference between corresponding entries
    606         * @see #meanDifference(double[],double[])
    607         * @return variance of paired differences
    608         * @throws IllegalArgumentException if the arrays do not have the same
    609         * length or their common length is less than 2.
    610         */
    611        public static double varianceDifference(final double[] sample1, final double[] sample2,
    612                double meanDifference)  throws IllegalArgumentException {
    613            double sum1 = 0d;
    614            double sum2 = 0d;
    615            double diff = 0d;
    616            int n = sample1.length;
    617            if (n != sample2.length) {
    618                throw MathRuntimeException.createIllegalArgumentException(
    619                      LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, n, sample2.length);
    620            }
    621            if (n < 2) {
    622                throw MathRuntimeException.createIllegalArgumentException(
    623                      LocalizedFormats.INSUFFICIENT_DIMENSION, n, 2);
    624            }
    625            for (int i = 0; i < n; i++) {
    626                diff = sample1[i] - sample2[i];
    627                sum1 += (diff - meanDifference) *(diff - meanDifference);
    628                sum2 += diff - meanDifference;
    629            }
    630            return (sum1 - (sum2 * sum2 / n)) / (n - 1);
    631        }
    632
    633
    634        /**
    635         * Normalize (standardize) the series, so in the end it is having a mean of 0 and a standard deviation of 1.
    636         *
    637         * @param sample sample to normalize
    638         * @return normalized (standardized) sample
    639         * @since 2.2
    640         */
    641        public static double[] normalize(final double[] sample) {
    642            DescriptiveStatistics stats = new DescriptiveStatistics();
    643
    644            // Add the data from the series to stats
    645            for (int i = 0; i < sample.length; i++) {
    646                stats.addValue(sample[i]);
    647            }
    648
    649            // Compute mean and standard deviation
    650            double mean = stats.getMean();
    651            double standardDeviation = stats.getStandardDeviation();
    652
    653            // initialize the standardizedSample, which has the same length as the sample
    654            double[] standardizedSample = new double[sample.length];
    655
    656            for (int i = 0; i < sample.length; i++) {
    657                // z = (x- mean)/standardDeviation
    658                standardizedSample[i] = (sample[i] - mean) / standardDeviation;
    659            }
    660            return standardizedSample;
    661        }
    662
    663    }