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.stat.descriptive.AbstractStorelessUnivariateStatistic;
022 import org.apache.commons.math.stat.descriptive.WeightedEvaluation;
023
024 /**
025 * Returns the product of the available values.
026 * <p>
027 * If there are no values in the dataset, or any of the values are
028 * <code>NaN</code>, then <code>NaN</code> is returned.</p>
029 * <p>
030 * <strong>Note that this implementation is not synchronized.</strong> If
031 * multiple threads access an instance of this class concurrently, and at least
032 * one of the threads invokes the <code>increment()</code> or
033 * <code>clear()</code> method, it must be synchronized externally.</p>
034 *
035 * @version $Revision: 917270 $ $Date: 2010-02-28 14:37:53 -0500 (Sun, 28 Feb 2010) $
036 */
037 public class Product extends AbstractStorelessUnivariateStatistic implements Serializable, WeightedEvaluation {
038
039 /** Serializable version identifier */
040 private static final long serialVersionUID = 2824226005990582538L;
041
042 /**The number of values that have been added */
043 private long n;
044
045 /**
046 * The current Running Product.
047 */
048 private double value;
049
050 /**
051 * Create a Product instance
052 */
053 public Product() {
054 n = 0;
055 value = Double.NaN;
056 }
057
058 /**
059 * Copy constructor, creates a new {@code Product} identical
060 * to the {@code original}
061 *
062 * @param original the {@code Product} instance to copy
063 */
064 public Product(Product original) {
065 copy(original, this);
066 }
067
068 /**
069 * {@inheritDoc}
070 */
071 @Override
072 public void increment(final double d) {
073 if (n == 0) {
074 value = d;
075 } else {
076 value *= d;
077 }
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 = Double.NaN;
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 Double.NaN 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)) {
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 Double.NaN 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)) {
163 product = 1.0;
164 for (int i = begin; i < begin + length; i++) {
165 product *= Math.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 NullPointerException if either source or dest is null
216 */
217 public static void copy(Product source, Product dest) {
218 dest.n = source.n;
219 dest.value = source.value;
220 }
221
222 }