001    /*
002     * Statistics
003     * 
004     * Copyright (c) 2003 Marco Schmidt.
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.util;
009    
010    /**
011     * A number of static methods to compute statistical properties of an
012     * array of double values.
013     * Implements the computation of mean, variance and standard deviation
014     * for <code>double</code> values.
015     * @author Marco Schmidt
016     * @since 0.11.0
017     */
018    public class Statistics
019    {
020            private Statistics()
021            {
022            }
023    
024            /**
025             * Computes the mean value for the argument array.
026             * Adds all values and divides them by the number of array elements.
027             * @param values double array on which the mean is to be determined
028             * @return computed mean value
029             * @throws IllegalArgumentException if the array has not at least one element
030             */
031            public static double computeMean(double[] values)
032            {
033                    return computeMean(values, 0, values.length);
034            }
035    
036            /**
037             * Computes the mean value for some elements of the argument array.
038             * Adds all values and divides them by the number of array elements.
039             * @param values array from which elements are read
040             * @param offset index of the first element to be used
041             * @param number number of elements to be used
042             * @return computed mean value
043             * @throws IllegalArgumentException if the array has not at least one element
044             */
045            public static double computeMean(double[] values, int offset, int number)
046            {
047                    if (number < 1)
048                    {
049                            throw new IllegalArgumentException("The number of values to process must be one or larger.");
050                    }
051                    double sum = 0;
052                    final int UNTIL = offset + number;
053                    do
054                    {
055                            sum += values[offset++];
056                    }
057                    while (offset != UNTIL);
058                    return sum / number; 
059            }
060    
061            /**
062             * Computes the standard deviation for the argument array of values.
063             * @param values array from which elements are read
064             * @return computed standard deviation
065             * @throws IllegalArgumentException if the array has not at least two elements
066             */
067            public static double computeStandardDeviation(double[] values)
068            {
069                    return computeStandardDeviation(values, 0, values.length);
070            }
071    
072            /**
073             * Computes the standard deviation for the argument array of values.
074             * Reuses the mean value for that argument which must have been computed before.
075             * @param values array from which elements are read
076             * @param mean the mean value for the array, possibly computed with a 
077             *   call to {@link #computeMean(double[])}.
078             * @return computed standard deviation
079             * @throws IllegalArgumentException if the array has not at least two elements
080             */
081            public static double computeStandardDeviation(double[] values, double mean)
082            {
083                    return computeStandardDeviation(values, 0, values.length, mean);
084            }
085    
086            /**
087             * Computes the standard deviation for some of the argument array's values.
088             * If you already have computed a mean value using {@link #computeMean(double[], int, int)},
089             * better call {@link #computeStandardDeviation(double[], int, int, double)}.
090             * Otherwise, this method has to compute mean again.
091             * @param values array from which elements are read
092             * @param offset first element to be used
093             * @param number number of elements used starting at values[offset]
094             * @return computed standard deviation
095             * @throws IllegalArgumentException if the array has not at least two elements
096             */
097            public static double computeStandardDeviation(double[] values, int offset, int number)
098            {
099                    double mean = computeMean(values, offset, number);
100                    return computeStandardDeviation(values, 0, values.length, mean);
101            }
102    
103            /**
104             * Computes the standard deviation for some of the argument array's values.
105             * Use this version of the method if you already have a mean value,
106             * otherwise this method must be computed again.
107             * @param values array from which elements are read
108             * @param offset first element to be used
109             * @param number number of elements used starting at values[offset]
110             * @param mean value of the elements
111             * @return computed standard deviation
112             * @throws IllegalArgumentException if the array has not at least two elements
113             */
114            public static double computeStandardDeviation(double[] values, int offset, int number, double mean)
115            {
116                    return Math.sqrt(computeVariance(values, offset, number, mean));
117            }
118    
119            /**
120             * Computes the variance for the argument array.
121             * @param values array from which elements are read
122             * @return variance for the array elements
123             * @throws IllegalArgumentException if the array has not at least two elements
124             */
125            public static double computeVariance(final double[] values)
126            {
127                    return computeVariance(values, 0, values.length);
128            }
129    
130            /**
131             * Computes the variance for some of the argument array's values.
132             * @param values array from which elements are read
133             * @param mean the mean for the array elements
134             * @return variance for the array elements
135             * @throws IllegalArgumentException if the array has not at least two elements
136             */
137            public static double computeVariance(final double[] values, final double mean)
138            {
139                    return computeVariance(values, 0, values.length, mean);
140            }
141    
142            /**
143             * Computes the variance for some of the argument array's values.
144             * If you already have computed a mean value using {@link #computeMean(double[], int, int)},
145             * better call {@link #computeVariance(double[], int, int, double)}.
146             * Otherwise, this method has to compute mean again.
147             * @param values array from which elements are read
148             * @param offset first element to be used
149             * @param number number of elements used starting at values[offset]
150             * @return computed variance
151             * @throws IllegalArgumentException if the array has not at least two elements
152             */
153            public static double computeVariance(final double[] values, int offset, final int number)
154            {
155                    double mean = computeMean(values, offset, number);
156                    return computeVariance(values, 0, values.length, mean);
157            }
158    
159            /**
160             * Computes the variance for some of the argument array's values.
161             * Use this version of the method in case mean has already been
162             * computed.
163             * @param values array from which elements are read
164             * @param offset first element to be used
165             * @param number number of elements used starting at values[offset]
166             * @param mean the mean for the array elements
167             * @return computed variance
168             * @throws IllegalArgumentException if the array has not at least two elements
169             */
170            public static double computeVariance(final double[] values, int offset, final int number, final double mean)
171            {
172                    if (number < 2)
173                    {
174                            throw new IllegalArgumentException("The number of values to process must be two or larger.");
175                    }
176                    double sum = 0;
177                    final int UNTIL = offset + number;
178                    do
179                    {
180                            double diff = values[offset++] - mean;
181                            sum += diff * diff;
182                    }
183                    while (offset != UNTIL);
184                    return sum / (number - 1); 
185            }
186    }