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.descriptive.moment;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
022    import org.apache.commons.math.stat.descriptive.summary.Sum;
023    
024    /**
025     * <p>Computes the arithmetic mean of a set of values. Uses the definitional 
026     * formula:</p>
027     * <p>
028     * mean = sum(x_i) / n
029     * </p>
030     * <p>where <code>n</code> is the number of observations.
031     * </p>
032     * <p>When {@link #increment(double)} is used to add data incrementally from a
033     * stream of (unstored) values, the value of the statistic that 
034     * {@link #getResult()} returns is computed using the following recursive
035     * updating algorithm: </p>
036     * <ol>
037     * <li>Initialize <code>m = </code> the first value</li>
038     * <li>For each additional value, update using <br>
039     *   <code>m = m + (new value - m) / (number of observations)</code></li>
040     * </ol>
041     * <p> If {@link #evaluate(double[])} is used to compute the mean of an array
042     * of stored values, a two-pass, corrected algorithm is used, starting with
043     * the definitional formula computed using the array of stored values and then
044     * correcting this by adding the mean deviation of the data values from the
045     * arithmetic mean. See, e.g. "Comparison of Several Algorithms for Computing
046     * Sample Means and Variances," Robert F. Ling, Journal of the American
047     * Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. 859-866. </p>
048     * <p>
049     *  Returns <code>Double.NaN</code> if the dataset is empty.
050     * </p>
051     * <strong>Note that this implementation is not synchronized.</strong> If 
052     * multiple threads access an instance of this class concurrently, and at least
053     * one of the threads invokes the <code>increment()</code> or 
054     * <code>clear()</code> method, it must be synchronized externally.
055     * 
056     * @version $Revision: 762116 $ $Date: 2009-04-05 12:48:53 -0400 (Sun, 05 Apr 2009) $
057     */
058    public class Mean extends AbstractStorelessUnivariateStatistic 
059        implements Serializable {
060    
061        /** Serializable version identifier */
062        private static final long serialVersionUID = -1296043746617791564L;    
063        
064        /** First moment on which this statistic is based. */
065        protected FirstMoment moment;
066    
067        /** 
068         * Determines whether or not this statistic can be incremented or cleared.
069         * <p>
070         * Statistics based on (constructed from) external moments cannot
071         * be incremented or cleared.</p>
072         */
073        protected boolean incMoment;
074    
075        /** Constructs a Mean. */
076        public Mean() {
077            incMoment = true;
078            moment = new FirstMoment();
079        }
080    
081        /**
082         * Constructs a Mean with an External Moment.
083         * 
084         * @param m1 the moment
085         */
086        public Mean(final FirstMoment m1) {
087            this.moment = m1;
088            incMoment = false;
089        }
090        
091        /**
092         * Copy constructor, creates a new {@code Mean} identical
093         * to the {@code original}
094         * 
095         * @param original the {@code Mean} instance to copy
096         */
097        public Mean(Mean original) {
098            copy(original, this);
099        }
100    
101        /**
102         * {@inheritDoc}
103         */
104        @Override
105        public void increment(final double d) {
106            if (incMoment) {
107                moment.increment(d);
108            }
109        }
110    
111        /**
112         * {@inheritDoc}
113         */
114        @Override
115        public void clear() {
116            if (incMoment) {
117                moment.clear();
118            }
119        }
120    
121        /**
122         * {@inheritDoc}
123         */
124        @Override
125        public double getResult() {
126            return moment.m1;
127        }
128    
129        /**
130         * {@inheritDoc}
131         */
132        public long getN() {
133            return moment.getN();
134        }
135    
136        /**
137         * Returns the arithmetic mean of the entries in the specified portion of
138         * the input array, or <code>Double.NaN</code> if the designated subarray
139         * is empty.
140         * <p>
141         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
142         * <p>
143         * See {@link Mean} for details on the computing algorithm.</p>
144         * 
145         * @param values the input array
146         * @param begin index of the first array element to include
147         * @param length the number of elements to include
148         * @return the mean of the values or Double.NaN if length = 0
149         * @throws IllegalArgumentException if the array is null or the array index
150         *  parameters are not valid
151         */
152        @Override
153        public double evaluate(final double[] values,final int begin, final int length) {
154            if (test(values, begin, length)) {
155                Sum sum = new Sum();
156                double sampleSize = length;
157                
158                // Compute initial estimate using definitional formula
159                double xbar = sum.evaluate(values, begin, length) / sampleSize;
160                
161                // Compute correction factor in second pass
162                double correction = 0;
163                for (int i = begin; i < begin + length; i++) {
164                    correction += (values[i] - xbar);
165                }
166                return xbar + (correction/sampleSize);
167            }
168            return Double.NaN;
169        }
170        
171        /**
172         * {@inheritDoc}
173         */
174        @Override
175        public Mean copy() {
176            Mean result = new Mean();
177            copy(this, result);
178            return result;
179        }
180        
181        
182        /**
183         * Copies source to dest.
184         * <p>Neither source nor dest can be null.</p>
185         * 
186         * @param source Mean to copy
187         * @param dest Mean to copy to
188         * @throws NullPointerException if either source or dest is null
189         */
190        public static void copy(Mean source, Mean dest) {
191            dest.incMoment = source.incMoment;
192            dest.moment = source.moment.copy();
193        }
194    }