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    
022    /**
023     * Computes a statistic related to the Third Central Moment.  Specifically,
024     * what is computed is the sum of cubed deviations from the sample mean.
025     * <p>
026     * The following recursive updating formula is used:</p>
027     * <p>
028     * Let <ul>
029     * <li> dev = (current obs - previous mean) </li>
030     * <li> m2 = previous value of {@link SecondMoment} </li>
031     * <li> n = number of observations (including current obs) </li>
032     * </ul>
033     * Then</p>
034     * <p>
035     * new value = old value - 3 * (dev/n) * m2 + (n-1) * (n -2) * (dev^3/n^2)</p>
036     * <p>
037     * Returns <code>Double.NaN</code> if no data values have been added and
038     * returns <code>0</code> if there is just one value in the data set.</p>
039     * <p>
040     * <strong>Note that this implementation is not synchronized.</strong> If 
041     * multiple threads access an instance of this class concurrently, and at least
042     * one of the threads invokes the <code>increment()</code> or 
043     * <code>clear()</code> method, it must be synchronized externally.</p>
044     * 
045     * @version $Revision: 762116 $ $Date: 2009-04-05 12:48:53 -0400 (Sun, 05 Apr 2009) $
046     */
047    public class ThirdMoment extends SecondMoment implements Serializable {
048    
049        /** Serializable version identifier */
050        private static final long serialVersionUID = -7818711964045118679L;  
051          
052        /** third moment of values that have been added */
053        protected double m3;
054    
055         /**
056         * Square of deviation of most recently added value from previous first 
057         * moment, normalized by previous sample size.  Retained to prevent 
058         * repeated computation in higher order moments.  nDevSq = nDev * nDev.
059         */
060        protected double nDevSq;
061    
062        /**
063         * Create a FourthMoment instance
064         */
065        public ThirdMoment() {
066            super();
067            m3 = Double.NaN;
068            nDevSq = Double.NaN;
069        }
070        
071        /**
072         * Copy constructor, creates a new {@code ThirdMoment} identical
073         * to the {@code original}
074         * 
075         * @param original the {@code ThirdMoment} instance to copy
076         */
077        public ThirdMoment(ThirdMoment original) {
078            copy(original, this);
079        }
080    
081        /**
082         * {@inheritDoc}
083         */
084        @Override
085        public void increment(final double d) {
086            if (n < 1) {
087                m3 = m2 = m1 = 0.0;
088            }  
089           
090            double prevM2 = m2;
091            super.increment(d);
092            nDevSq = nDev * nDev;
093            double n0 = n;
094            m3 = m3 - 3.0 * nDev * prevM2 + (n0 - 1) * (n0 - 2) * nDevSq * dev;
095        }
096    
097        /**
098         * {@inheritDoc}
099         */
100        @Override
101        public double getResult() {
102            return m3;
103        }
104    
105        /**
106         * {@inheritDoc}
107         */
108        @Override
109        public void clear() {
110            super.clear();
111            m3 = Double.NaN;
112            nDevSq = Double.NaN;
113        }
114        
115        /**
116         * {@inheritDoc}
117         */
118        @Override
119        public ThirdMoment copy() {
120            ThirdMoment result = new ThirdMoment();
121            copy(this, result);
122            return result; 
123        }
124        
125        /**
126         * Copies source to dest.
127         * <p>Neither source nor dest can be null.</p>
128         * 
129         * @param source ThirdMoment to copy
130         * @param dest ThirdMoment to copy to
131         * @throws NullPointerException if either source or dest is null
132         */
133        public static void copy(ThirdMoment source, ThirdMoment dest) {
134            SecondMoment.copy(source, dest);
135            dest.m3 = source.m3;
136            dest.nDevSq = source.nDevSq;
137        }
138    
139    }