View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.stat.descriptive.moment;
23  
24  import java.io.Serializable;
25  
26  import org.hipparchus.exception.NullArgumentException;
27  import org.hipparchus.stat.descriptive.AbstractStorelessUnivariateStatistic;
28  import org.hipparchus.util.MathUtils;
29  
30  /**
31   * Computes the first moment (arithmetic mean). Uses the definitional formula:
32   * <p>
33   * mean = sum(x_i) / n
34   * <p>
35   * where <code>n</code> is the number of observations.
36   * <p>
37   * To limit numeric errors, the value of the statistic is computed using the
38   * following recursive updating algorithm:
39   * </p>
40   * <ol>
41   * <li>Initialize <code>m = </code> the first value</li>
42   * <li>For each additional value, update using <br>
43   *   <code>m = m + (new value - m) / (number of observations)</code></li>
44   * </ol>
45   * <p>
46   * Returns <code>Double.NaN</code> if the dataset is empty. Note that
47   * Double.NaN may also be returned if the input includes NaN and / or infinite
48   * values.
49   * <p>
50   * <strong>Note that this implementation is not synchronized.</strong> If
51   * multiple threads access an instance of this class concurrently, and at least
52   * one of the threads invokes the <code>increment()</code> or
53   * <code>clear()</code> method, it must be synchronized externally.
54   */
55  class FirstMoment extends AbstractStorelessUnivariateStatistic
56      implements Serializable {
57  
58      /** Serializable version identifier */
59      private static final long serialVersionUID = 20150412L;
60  
61      /** Count of values that have been added */
62      protected long n;
63  
64      /** First moment of values that have been added */
65      protected double m1;
66  
67      /**
68       * Deviation of most recently added value from previous first moment.
69       * Retained to prevent repeated computation in higher order moments.
70       */
71      protected double dev;
72  
73      /**
74       * Deviation of most recently added value from previous first moment,
75       * normalized by previous sample size.  Retained to prevent repeated
76       * computation in higher order moments.
77       */
78      protected double nDev;
79  
80      /**
81       * Create a FirstMoment instance.
82       */
83      FirstMoment() {
84          n = 0;
85          m1 = Double.NaN;
86          dev = Double.NaN;
87          nDev = Double.NaN;
88      }
89  
90      /**
91       * Copy constructor, creates a new {@code FirstMoment} identical
92       * to the {@code original}
93       *
94       * @param original the {@code FirstMoment} instance to copy
95       * @throws NullArgumentException if original is null
96       */
97       FirstMoment(FirstMoment original) throws NullArgumentException {
98           MathUtils.checkNotNull(original);
99           this.n    = original.n;
100          this.m1   = original.m1;
101          this.dev  = original.dev;
102          this.nDev = original.nDev;
103      }
104 
105     /** {@inheritDoc} */
106      @Override
107     public void increment(final double d) {
108         if (n == 0) {
109             m1 = 0.0;
110         }
111         n++;
112         double n0 = n;
113         dev = d - m1;
114         nDev = dev / n0;
115         m1 += nDev;
116     }
117 
118     /** {@inheritDoc} */
119     @Override
120     public void clear() {
121         m1 = Double.NaN;
122         n = 0;
123         dev = Double.NaN;
124         nDev = Double.NaN;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public double getResult() {
130         return m1;
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public long getN() {
136         return n;
137     }
138 
139     /**
140      * Aggregates the results of the provided instance
141      * into this instance.
142      *
143      * @param other the instance to aggregate from
144      */
145     protected void aggregate(FirstMoment other) {
146         MathUtils.checkNotNull(other);
147         if (other.n > 0) {
148             if (this.n == 0) {
149                 this.m1 = 0.0;
150             }
151             this.n   += other.n;
152             this.dev  = other.m1 - this.m1;
153             this.nDev = this.dev / this.n;
154             this.m1  += other.n / (double) this.n * this.dev;
155         }
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public FirstMoment copy() {
161         return new FirstMoment(this);
162     }
163 
164 }