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