1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.math4.legacy.stat.descriptive.summary;
18
19 import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
20 import org.apache.commons.math4.legacy.exception.NullArgumentException;
21 import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic;
22 import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation;
23 import org.apache.commons.math4.core.jdkmath.JdkMath;
24 import org.apache.commons.math4.legacy.core.MathArrays;
25
26 /**
27 * Returns the product of the available values.
28 * <p>
29 * If there are no values in the dataset, then 1 is returned.
30 * If any of the values are
31 * <code>NaN</code>, then <code>NaN</code> is returned.</p>
32 * <p>
33 * <strong>Note that this implementation is not synchronized.</strong> If
34 * multiple threads access an instance of this class concurrently, and at least
35 * one of the threads invokes the <code>increment()</code> or
36 * <code>clear()</code> method, it must be synchronized externally.</p>
37 */
38 public class Product extends AbstractStorelessUnivariateStatistic implements WeightedEvaluation {
39 /**The number of values that have been added. */
40 private long n;
41
42 /**
43 * The current Running Product.
44 */
45 private double value;
46
47 /**
48 * Create a Product instance.
49 */
50 public Product() {
51 n = 0;
52 value = 1;
53 }
54
55 /**
56 * Copy constructor, creates a new {@code Product} identical
57 * to the {@code original}.
58 *
59 * @param original the {@code Product} instance to copy
60 * @throws NullArgumentException if original is null
61 */
62 public Product(Product original) throws NullArgumentException {
63 copy(original, this);
64 }
65
66 /**
67 * {@inheritDoc}
68 */
69 @Override
70 public void increment(final double d) {
71 value *= d;
72 n++;
73 }
74
75 /**
76 * {@inheritDoc}
77 */
78 @Override
79 public double getResult() {
80 return value;
81 }
82
83 /**
84 * {@inheritDoc}
85 */
86 @Override
87 public long getN() {
88 return n;
89 }
90
91 /**
92 * {@inheritDoc}
93 */
94 @Override
95 public void clear() {
96 value = 1;
97 n = 0;
98 }
99
100 /**
101 * Returns the product of the entries in the specified portion of
102 * the input array, or <code>Double.NaN</code> if the designated subarray
103 * is empty.
104 * <p>
105 * Throws <code>MathIllegalArgumentException</code> if the array is null.</p>
106 *
107 * @param values the input array
108 * @param begin index of the first array element to include
109 * @param length the number of elements to include
110 * @return the product of the values or 1 if length = 0
111 * @throws MathIllegalArgumentException if the array is null or the array index
112 * parameters are not valid
113 */
114 @Override
115 public double evaluate(final double[] values, final int begin, final int length)
116 throws MathIllegalArgumentException {
117 double product = Double.NaN;
118 if (MathArrays.verifyValues(values, begin, length, true)) {
119 product = 1.0;
120 for (int i = begin; i < begin + length; i++) {
121 product *= values[i];
122 }
123 }
124 return product;
125 }
126
127 /**
128 * <p>Returns the weighted product of the entries in the specified portion of
129 * the input array, or <code>Double.NaN</code> if the designated subarray
130 * is empty.</p>
131 *
132 * <p>Throws <code>MathIllegalArgumentException</code> if any of the following are true:
133 * <ul><li>the values array is null</li>
134 * <li>the weights array is null</li>
135 * <li>the weights array does not have the same length as the values array</li>
136 * <li>the weights array contains one or more infinite values</li>
137 * <li>the weights array contains one or more NaN values</li>
138 * <li>the weights array contains negative values</li>
139 * <li>the start and length arguments do not determine a valid array</li>
140 * </ul>
141 *
142 * <p>Uses the formula, <div style="white-space: pre"><code>
143 * weighted product = ∏values[i]<sup>weights[i]</sup>
144 * </code></div>
145 * that is, the weights are applied as exponents when computing the weighted product.
146 *
147 * @param values the input array
148 * @param weights the weights array
149 * @param begin index of the first array element to include
150 * @param length the number of elements to include
151 * @return the product of the values or 1 if length = 0
152 * @throws MathIllegalArgumentException if the parameters are not valid
153 * @since 2.1
154 */
155 @Override
156 public double evaluate(final double[] values, final double[] weights,
157 final int begin, final int length) throws MathIllegalArgumentException {
158 double product = Double.NaN;
159 if (MathArrays.verifyValues(values, weights, begin, length, true)) {
160 product = 1.0;
161 for (int i = begin; i < begin + length; i++) {
162 product *= JdkMath.pow(values[i], weights[i]);
163 }
164 }
165 return product;
166 }
167
168 /**
169 * <p>Returns the weighted product of the entries in the input array.</p>
170 *
171 * <p>Throws <code>MathIllegalArgumentException</code> if any of the following are true:
172 * <ul><li>the values array is null</li>
173 * <li>the weights array is null</li>
174 * <li>the weights array does not have the same length as the values array</li>
175 * <li>the weights array contains one or more infinite values</li>
176 * <li>the weights array contains one or more NaN values</li>
177 * <li>the weights array contains negative values</li>
178 * </ul>
179 *
180 * <p>Uses the formula,
181 * <div style="white-space: pre"><code>
182 * weighted product = ∏values[i]<sup>weights[i]</sup>
183 * </code></div>
184 * that is, the weights are applied as exponents when computing the weighted product.
185 *
186 * @param values the input array
187 * @param weights the weights array
188 * @return the product of the values or Double.NaN if length = 0
189 * @throws MathIllegalArgumentException if the parameters are not valid
190 * @since 2.1
191 */
192 @Override
193 public double evaluate(final double[] values, final double[] weights) throws MathIllegalArgumentException {
194 return evaluate(values, weights, 0, values.length);
195 }
196
197 /**
198 * {@inheritDoc}
199 */
200 @Override
201 public Product copy() {
202 Product result = new Product();
203 // No try-catch or advertised exception because args are valid
204 copy(this, result);
205 return result;
206 }
207
208 /**
209 * Copies source to dest.
210 * <p>Neither source nor dest can be null.</p>
211 *
212 * @param source Product to copy
213 * @param dest Product to copy to
214 * @throws NullArgumentException if either source or dest is null
215 */
216 public static void copy(Product source, Product dest)
217 throws NullArgumentException {
218 NullArgumentException.check(source);
219 NullArgumentException.check(dest);
220 dest.n = source.n;
221 dest.value = source.value;
222 }
223 }