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.stat.descriptive.WeightedEvaluation;
024 import org.apache.commons.math.util.FastMath;
025 import org.apache.commons.math.util.MathUtils;
026
027 /**
028 * Returns the product of the available values.
029 * <p>
030 * If there are no values in the dataset, then 1 is returned.
031 * If any of the values are
032 * <code>NaN</code>, then <code>NaN</code> is returned.</p>
033 * <p>
034 * <strong>Note that this implementation is not synchronized.</strong> If
035 * multiple threads access an instance of this class concurrently, and at least
036 * one of the threads invokes the <code>increment()</code> or
037 * <code>clear()</code> method, it must be synchronized externally.</p>
038 *
039 * @version $Id: Product.java 1132432 2011-06-05 14:59:29Z luc $
040 */
041 public class Product extends AbstractStorelessUnivariateStatistic implements Serializable, WeightedEvaluation {
042
043 /** Serializable version identifier */
044 private static final long serialVersionUID = 2824226005990582538L;
045
046 /**The number of values that have been added */
047 private long n;
048
049 /**
050 * The current Running Product.
051 */
052 private double value;
053
054 /**
055 * Create a Product instance
056 */
057 public Product() {
058 n = 0;
059 value = 1;
060 }
061
062 /**
063 * Copy constructor, creates a new {@code Product} identical
064 * to the {@code original}
065 *
066 * @param original the {@code Product} instance to copy
067 */
068 public Product(Product original) {
069 copy(original, this);
070 }
071
072 /**
073 * {@inheritDoc}
074 */
075 @Override
076 public void increment(final double d) {
077 value *= d;
078 n++;
079 }
080
081 /**
082 * {@inheritDoc}
083 */
084 @Override
085 public double getResult() {
086 return value;
087 }
088
089 /**
090 * {@inheritDoc}
091 */
092 public long getN() {
093 return n;
094 }
095
096 /**
097 * {@inheritDoc}
098 */
099 @Override
100 public void clear() {
101 value = 1;
102 n = 0;
103 }
104
105 /**
106 * Returns the product of the entries in the specified portion of
107 * the input array, or <code>Double.NaN</code> if the designated subarray
108 * is empty.
109 * <p>
110 * Throws <code>IllegalArgumentException</code> if the array is null.</p>
111 *
112 * @param values the input array
113 * @param begin index of the first array element to include
114 * @param length the number of elements to include
115 * @return the product of the values or 1 if length = 0
116 * @throws IllegalArgumentException if the array is null or the array index
117 * parameters are not valid
118 */
119 @Override
120 public double evaluate(final double[] values, final int begin, final int length) {
121 double product = Double.NaN;
122 if (test(values, begin, length, true)) {
123 product = 1.0;
124 for (int i = begin; i < begin + length; i++) {
125 product *= values[i];
126 }
127 }
128 return product;
129 }
130
131 /**
132 * <p>Returns the weighted product of the entries in the specified portion of
133 * the input array, or <code>Double.NaN</code> if the designated subarray
134 * is empty.</p>
135 *
136 * <p>Throws <code>IllegalArgumentException</code> if any of the following are true:
137 * <ul><li>the values array is null</li>
138 * <li>the weights array is null</li>
139 * <li>the weights array does not have the same length as the values array</li>
140 * <li>the weights array contains one or more infinite values</li>
141 * <li>the weights array contains one or more NaN values</li>
142 * <li>the weights array contains negative values</li>
143 * <li>the start and length arguments do not determine a valid array</li>
144 * </ul></p>
145 *
146 * <p>Uses the formula, <pre>
147 * weighted product = ∏values[i]<sup>weights[i]</sup>
148 * </pre>
149 * that is, the weights are applied as exponents when computing the weighted product.</p>
150 *
151 * @param values the input array
152 * @param weights the weights array
153 * @param begin index of the first array element to include
154 * @param length the number of elements to include
155 * @return the product of the values or 1 if length = 0
156 * @throws IllegalArgumentException if the parameters are not valid
157 * @since 2.1
158 */
159 public double evaluate(final double[] values, final double[] weights,
160 final int begin, final int length) {
161 double product = Double.NaN;
162 if (test(values, weights, begin, length, true)) {
163 product = 1.0;
164 for (int i = begin; i < begin + length; i++) {
165 product *= FastMath.pow(values[i], weights[i]);
166 }
167 }
168 return product;
169 }
170
171 /**
172 * <p>Returns the weighted product of the entries in the input array.</p>
173 *
174 * <p>Throws <code>IllegalArgumentException</code> if any of the following are true:
175 * <ul><li>the values array is null</li>
176 * <li>the weights array is null</li>
177 * <li>the weights array does not have the same length as the values array</li>
178 * <li>the weights array contains one or more infinite values</li>
179 * <li>the weights array contains one or more NaN values</li>
180 * <li>the weights array contains negative values</li>
181 * </ul></p>
182 *
183 * <p>Uses the formula, <pre>
184 * weighted product = ∏values[i]<sup>weights[i]</sup>
185 * </pre>
186 * that is, the weights are applied as exponents when computing the weighted product.</p>
187 *
188 * @param values the input array
189 * @param weights the weights array
190 * @return the product of the values or Double.NaN if length = 0
191 * @throws IllegalArgumentException if the parameters are not valid
192 * @since 2.1
193 */
194 public double evaluate(final double[] values, final double[] weights) {
195 return evaluate(values, weights, 0, values.length);
196 }
197
198
199 /**
200 * {@inheritDoc}
201 */
202 @Override
203 public Product copy() {
204 Product result = new Product();
205 copy(this, result);
206 return result;
207 }
208
209 /**
210 * Copies source to dest.
211 * <p>Neither source nor dest can be null.</p>
212 *
213 * @param source Product to copy
214 * @param dest Product to copy to
215 * @throws NullArgumentException if either source or dest is null
216 */
217 public static void copy(Product source, Product dest)
218 throws NullArgumentException {
219 MathUtils.checkNotNull(source);
220 MathUtils.checkNotNull(dest);
221 dest.setData(source.getDataRef());
222 dest.n = source.n;
223 dest.value = source.value;
224 }
225
226 }