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.summary;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.math.exception.NullArgumentException;
022    import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
023    import org.apache.commons.math.util.FastMath;
024    import org.apache.commons.math.util.MathUtils;
025    
026    /**
027     * Returns the sum of the natural logs for this collection of values.
028     * <p>
029     * Uses {@link org.apache.commons.math.util.FastMath#log(double)} to compute the logs.
030     * Therefore,
031     * <ul>
032     * <li>If any of values are &lt; 0, the result is <code>NaN.</code></li>
033     * <li>If all values are non-negative and less than
034     * <code>Double.POSITIVE_INFINITY</code>,  but at least one value is 0, the
035     * result is <code>Double.NEGATIVE_INFINITY.</code></li>
036     * <li>If both <code>Double.POSITIVE_INFINITY</code> and
037     * <code>Double.NEGATIVE_INFINITY</code> are among the values, the result is
038     * <code>NaN.</code></li>
039     * </ul></p>
040     * <p>
041     * <strong>Note that this implementation is not synchronized.</strong> If
042     * multiple threads access an instance of this class concurrently, and at least
043     * one of the threads invokes the <code>increment()</code> or
044     * <code>clear()</code> method, it must be synchronized externally.</p>
045     *
046     * @version $Id: SumOfLogs.java 1132432 2011-06-05 14:59:29Z luc $
047     */
048    public class SumOfLogs extends AbstractStorelessUnivariateStatistic implements Serializable {
049    
050        /** Serializable version identifier */
051        private static final long serialVersionUID = -370076995648386763L;
052    
053        /**Number of values that have been added */
054        private int n;
055    
056        /**
057         * The currently running value
058         */
059        private double value;
060    
061        /**
062         * Create a SumOfLogs instance
063         */
064        public SumOfLogs() {
065           value = 0d;
066           n = 0;
067        }
068    
069        /**
070         * Copy constructor, creates a new {@code SumOfLogs} identical
071         * to the {@code original}
072         *
073         * @param original the {@code SumOfLogs} instance to copy
074         */
075        public SumOfLogs(SumOfLogs original) {
076            copy(original, this);
077        }
078    
079        /**
080         * {@inheritDoc}
081         */
082        @Override
083        public void increment(final double d) {
084            value += FastMath.log(d);
085            n++;
086        }
087    
088        /**
089         * {@inheritDoc}
090         */
091        @Override
092        public double getResult() {
093            return value;
094        }
095    
096        /**
097         * {@inheritDoc}
098         */
099        public long getN() {
100            return n;
101        }
102    
103        /**
104         * {@inheritDoc}
105         */
106        @Override
107        public void clear() {
108            value = 0d;
109            n = 0;
110        }
111    
112        /**
113         * Returns the sum of the natural logs of the entries in the specified portion of
114         * the input array, or <code>Double.NaN</code> if the designated subarray
115         * is empty.
116         * <p>
117         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
118         * <p>
119         * See {@link SumOfLogs}.</p>
120         *
121         * @param values the input array
122         * @param begin index of the first array element to include
123         * @param length the number of elements to include
124         * @return the sum of the natural logs of the values or 0 if
125         * length = 0
126         * @throws IllegalArgumentException if the array is null or the array index
127         *  parameters are not valid
128         */
129        @Override
130        public double evaluate(final double[] values, final int begin, final int length) {
131            double sumLog = Double.NaN;
132            if (test(values, begin, length, true)) {
133                sumLog = 0.0;
134                for (int i = begin; i < begin + length; i++) {
135                    sumLog += FastMath.log(values[i]);
136                }
137            }
138            return sumLog;
139        }
140    
141        /**
142         * {@inheritDoc}
143         */
144        @Override
145        public SumOfLogs copy() {
146            SumOfLogs result = new SumOfLogs();
147            copy(this, result);
148            return result;
149        }
150    
151        /**
152         * Copies source to dest.
153         * <p>Neither source nor dest can be null.</p>
154         *
155         * @param source SumOfLogs to copy
156         * @param dest SumOfLogs to copy to
157         * @throws NullArgumentException if either source or dest is null
158         */
159        public static void copy(SumOfLogs source, SumOfLogs dest)
160            throws NullArgumentException {
161            MathUtils.checkNotNull(source);
162            MathUtils.checkNotNull(dest);
163            dest.setData(source.getDataRef());
164            dest.n = source.n;
165            dest.value = source.value;
166        }
167    }