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 */
017package org.apache.commons.statistics.descriptive;
018
019/**
020 * Returns the product of the available values.
021 *
022 * <ul>
023 *   <li>The result is one if no values are observed.
024 *   <li>The result is {@code NaN} if any of the values is {@code NaN}.
025 * </ul>
026 *
027 * <p>This class is designed to work with (though does not require)
028 * {@linkplain java.util.stream streams}.
029 *
030 * <p><strong>This instance is not thread safe.</strong>
031 * If multiple threads access an instance of this class concurrently,
032 * and at least one of the threads invokes the {@link java.util.function.DoubleConsumer#accept(double) accept} or
033 * {@link StatisticAccumulator#combine(StatisticResult) combine} method, it must be synchronized externally.
034 *
035 * <p>However, it is safe to use {@link java.util.function.DoubleConsumer#accept(double) accept}
036 * and {@link StatisticAccumulator#combine(StatisticResult) combine}
037 * as {@code accumulator} and {@code combiner} functions of
038 * {@link java.util.stream.Collector Collector} on a parallel stream,
039 * because the parallel instance of {@link java.util.stream.Stream#collect Stream.collect()}
040 * provides the necessary partitioning, isolation, and merging of results for
041 * safe and efficient parallel execution.
042 *
043 * @since 1.1
044 */
045public final class Product implements DoubleStatistic, StatisticAccumulator<Product> {
046
047    /** Product of all values. */
048    private double productValue = 1;
049
050    /**
051     * Create an instance.
052     */
053    private Product() {
054        // No-op
055    }
056
057    /**
058     * Creates an instance.
059     *
060     * <p>The initial result is one.
061     *
062     * @return {@code Product} instance.
063     */
064    public static Product create() {
065        return new Product();
066    }
067
068    /**
069     * Returns an instance populated using the input {@code values}.
070     *
071     * <p>The result is {@code NaN} if any of the values is {@code NaN}
072     * or the product at any point is a {@code NaN}.
073     *
074     * <p>When the input is an empty array, the result is one.
075     *
076     * @param values Values.
077     * @return {@code Product} instance.
078     */
079    public static Product of(double... values) {
080        return Statistics.add(new Product(), values);
081    }
082
083    /**
084     * Returns an instance populated using the input {@code values}.
085     *
086     * <p>When the input is an empty array, the result is one.
087     *
088     * @param values Values.
089     * @return {@code Product} instance.
090     */
091    public static Product of(int... values) {
092        return Statistics.add(new Product(), values);
093    }
094
095    /**
096     * Returns an instance populated using the input {@code values}.
097     *
098     * <p>When the input is an empty array, the result is one.
099     *
100     * @param values Values.
101     * @return {@code Product} instance.
102     */
103    public static Product of(long... values) {
104        return Statistics.add(new Product(), values);
105    }
106
107    /**
108     * Updates the state of the statistic to reflect the addition of {@code value}.
109     *
110     * @param value Value.
111     */
112    @Override
113    public void accept(double value) {
114        this.productValue *= value;
115    }
116
117    /**
118     * Gets the product of all input values.
119     *
120     * <p>When no values have been added, the result is one.
121     *
122     * @return product of all values.
123     */
124    @Override
125    public double getAsDouble() {
126        return productValue;
127    }
128
129    @Override
130    public Product combine(Product other) {
131        productValue *= other.productValue;
132        return this;
133    }
134}