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