FirstMoment.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.stat.descriptive.moment;

  22. import java.io.Serializable;

  23. import org.hipparchus.exception.NullArgumentException;
  24. import org.hipparchus.stat.descriptive.AbstractStorelessUnivariateStatistic;
  25. import org.hipparchus.util.MathUtils;

  26. /**
  27.  * Computes the first moment (arithmetic mean). Uses the definitional formula:
  28.  * <p>
  29.  * mean = sum(x_i) / n
  30.  * <p>
  31.  * where <code>n</code> is the number of observations.
  32.  * <p>
  33.  * To limit numeric errors, the value of the statistic is computed using the
  34.  * following recursive updating algorithm:
  35.  * </p>
  36.  * <ol>
  37.  * <li>Initialize <code>m = </code> the first value</li>
  38.  * <li>For each additional value, update using <br>
  39.  *   <code>m = m + (new value - m) / (number of observations)</code></li>
  40.  * </ol>
  41.  * <p>
  42.  * Returns <code>Double.NaN</code> if the dataset is empty. Note that
  43.  * Double.NaN may also be returned if the input includes NaN and / or infinite
  44.  * values.
  45.  * <p>
  46.  * <strong>Note that this implementation is not synchronized.</strong> If
  47.  * multiple threads access an instance of this class concurrently, and at least
  48.  * one of the threads invokes the <code>increment()</code> or
  49.  * <code>clear()</code> method, it must be synchronized externally.
  50.  */
  51. class FirstMoment extends AbstractStorelessUnivariateStatistic
  52.     implements Serializable {

  53.     /** Serializable version identifier */
  54.     private static final long serialVersionUID = 20150412L;

  55.     /** Count of values that have been added */
  56.     protected long n;

  57.     /** First moment of values that have been added */
  58.     protected double m1;

  59.     /**
  60.      * Deviation of most recently added value from previous first moment.
  61.      * Retained to prevent repeated computation in higher order moments.
  62.      */
  63.     protected double dev;

  64.     /**
  65.      * Deviation of most recently added value from previous first moment,
  66.      * normalized by previous sample size.  Retained to prevent repeated
  67.      * computation in higher order moments.
  68.      */
  69.     protected double nDev;

  70.     /**
  71.      * Create a FirstMoment instance.
  72.      */
  73.     FirstMoment() {
  74.         n = 0;
  75.         m1 = Double.NaN;
  76.         dev = Double.NaN;
  77.         nDev = Double.NaN;
  78.     }

  79.     /**
  80.      * Copy constructor, creates a new {@code FirstMoment} identical
  81.      * to the {@code original}
  82.      *
  83.      * @param original the {@code FirstMoment} instance to copy
  84.      * @throws NullArgumentException if original is null
  85.      */
  86.      FirstMoment(FirstMoment original) throws NullArgumentException {
  87.          MathUtils.checkNotNull(original);
  88.          this.n    = original.n;
  89.          this.m1   = original.m1;
  90.          this.dev  = original.dev;
  91.          this.nDev = original.nDev;
  92.      }

  93.     /** {@inheritDoc} */
  94.      @Override
  95.     public void increment(final double d) {
  96.         if (n == 0) {
  97.             m1 = 0.0;
  98.         }
  99.         n++;
  100.         double n0 = n;
  101.         dev = d - m1;
  102.         nDev = dev / n0;
  103.         m1 += nDev;
  104.     }

  105.     /** {@inheritDoc} */
  106.     @Override
  107.     public void clear() {
  108.         m1 = Double.NaN;
  109.         n = 0;
  110.         dev = Double.NaN;
  111.         nDev = Double.NaN;
  112.     }

  113.     /** {@inheritDoc} */
  114.     @Override
  115.     public double getResult() {
  116.         return m1;
  117.     }

  118.     /** {@inheritDoc} */
  119.     @Override
  120.     public long getN() {
  121.         return n;
  122.     }

  123.     /**
  124.      * Aggregates the results of the provided instance
  125.      * into this instance.
  126.      *
  127.      * @param other the instance to aggregate from
  128.      */
  129.     protected void aggregate(FirstMoment other) {
  130.         MathUtils.checkNotNull(other);
  131.         if (other.n > 0) {
  132.             if (this.n == 0) {
  133.                 this.m1 = 0.0;
  134.             }
  135.             this.n   += other.n;
  136.             this.dev  = other.m1 - this.m1;
  137.             this.nDev = this.dev / this.n;
  138.             this.m1  += other.n / (double) this.n * this.dev;
  139.         }
  140.     }

  141.     /** {@inheritDoc} */
  142.     @Override
  143.     public FirstMoment copy() {
  144.         return new FirstMoment(this);
  145.     }

  146. }