diff -r 836adbf7a2cd -r 3317bb8137f4 jdk/src/java.base/share/classes/java/util/DoubleSummaryStatistics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/java/util/DoubleSummaryStatistics.java Sun Aug 17 15:54:13 2014 +0100 @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util; + +import java.util.function.DoubleConsumer; +import java.util.stream.Collector; + +/** + * A state object for collecting statistics such as count, min, max, sum, and + * average. + * + *

This class is designed to work with (though does not require) + * {@linkplain java.util.stream streams}. For example, you can compute + * summary statistics on a stream of doubles with: + *

 {@code
+ * DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new,
+ *                                                      DoubleSummaryStatistics::accept,
+ *                                                      DoubleSummaryStatistics::combine);
+ * }
+ * + *

{@code DoubleSummaryStatistics} can be used as a + * {@linkplain java.util.stream.Stream#collect(Collector) reduction} + * target for a {@linkplain java.util.stream.Stream stream}. For example: + * + *

 {@code
+ * DoubleSummaryStatistics stats = people.stream()
+ *     .collect(Collectors.summarizingDouble(Person::getWeight));
+ *}
+ * + * This computes, in a single pass, the count of people, as well as the minimum, + * maximum, sum, and average of their weights. + * + * @implNote This implementation is not thread safe. However, it is safe to use + * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction) + * Collectors.summarizingDouble()} on a parallel stream, because the parallel + * implementation of {@link java.util.stream.Stream#collect Stream.collect()} + * provides the necessary partitioning, isolation, and merging of results for + * safe and efficient parallel execution. + * @since 1.8 + */ +public class DoubleSummaryStatistics implements DoubleConsumer { + private long count; + private double sum; + private double sumCompensation; // Low order bits of sum + private double simpleSum; // Used to compute right sum for non-finite inputs + private double min = Double.POSITIVE_INFINITY; + private double max = Double.NEGATIVE_INFINITY; + + /** + * Construct an empty instance with zero count, zero sum, + * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY} + * max and zero average. + */ + public DoubleSummaryStatistics() { } + + /** + * Records another value into the summary information. + * + * @param value the input value + */ + @Override + public void accept(double value) { + ++count; + simpleSum += value; + sumWithCompensation(value); + min = Math.min(min, value); + max = Math.max(max, value); + } + + /** + * Combines the state of another {@code DoubleSummaryStatistics} into this + * one. + * + * @param other another {@code DoubleSummaryStatistics} + * @throws NullPointerException if {@code other} is null + */ + public void combine(DoubleSummaryStatistics other) { + count += other.count; + simpleSum += other.simpleSum; + sumWithCompensation(other.sum); + sumWithCompensation(other.sumCompensation); + min = Math.min(min, other.min); + max = Math.max(max, other.max); + } + + /** + * Incorporate a new double value using Kahan summation / + * compensated summation. + */ + private void sumWithCompensation(double value) { + double tmp = value - sumCompensation; + double velvel = sum + tmp; // Little wolf of rounding error + sumCompensation = (velvel - sum) - tmp; + sum = velvel; + } + + /** + * Return the count of values recorded. + * + * @return the count of values + */ + public final long getCount() { + return count; + } + + /** + * Returns the sum of values recorded, or zero if no values have been + * recorded. + * + *

The value of a floating-point sum is a function both of the + * input values as well as the order of addition operations. The + * order of addition operations of this method is intentionally + * not defined to allow for implementation flexibility to improve + * the speed and accuracy of the computed result. + * + * In particular, this method may be implemented using compensated + * summation or other technique to reduce the error bound in the + * numerical sum compared to a simple summation of {@code double} + * values. + * + * Because of the unspecified order of operations and the + * possibility of using differing summation schemes, the output of + * this method may vary on the same input values. + * + *

Various conditions can result in a non-finite sum being + * computed. This can occur even if the all the recorded values + * being summed are finite. If any recorded value is non-finite, + * the sum will be non-finite: + * + *

+ * + * It is possible for intermediate sums of finite values to + * overflow into opposite-signed infinities; if that occurs, the + * final sum will be NaN even if the recorded values are all + * finite. + * + * If all the recorded values are zero, the sign of zero is + * not guaranteed to be preserved in the final sum. + * + * @apiNote Values sorted by increasing absolute magnitude tend to yield + * more accurate results. + * + * @return the sum of values, or zero if none + */ + public final double getSum() { + // Better error bounds to add both terms as the final sum + double tmp = sum + sumCompensation; + if (Double.isNaN(tmp) && Double.isInfinite(simpleSum)) + // If the compensated sum is spuriously NaN from + // accumulating one or more same-signed infinite values, + // return the correctly-signed infinity stored in + // simpleSum. + return simpleSum; + else + return tmp; + } + + /** + * Returns the minimum recorded value, {@code Double.NaN} if any recorded + * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were + * recorded. Unlike the numerical comparison operators, this method + * considers negative zero to be strictly smaller than positive zero. + * + * @return the minimum recorded value, {@code Double.NaN} if any recorded + * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were + * recorded + */ + public final double getMin() { + return min; + } + + /** + * Returns the maximum recorded value, {@code Double.NaN} if any recorded + * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were + * recorded. Unlike the numerical comparison operators, this method + * considers negative zero to be strictly smaller than positive zero. + * + * @return the maximum recorded value, {@code Double.NaN} if any recorded + * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were + * recorded + */ + public final double getMax() { + return max; + } + + /** + * Returns the arithmetic mean of values recorded, or zero if no + * values have been recorded. + * + *

The computed average can vary numerically and have the + * special case behavior as computing the sum; see {@link #getSum} + * for details. + * + * @apiNote Values sorted by increasing absolute magnitude tend to yield + * more accurate results. + * + * @return the arithmetic mean of values, or zero if none + */ + public final double getAverage() { + return getCount() > 0 ? getSum() / getCount() : 0.0d; + } + + /** + * {@inheritDoc} + * + * Returns a non-empty string representation of this object suitable for + * debugging. The exact presentation format is unspecified and may vary + * between implementations and versions. + */ + @Override + public String toString() { + return String.format( + "%s{count=%d, sum=%f, min=%f, average=%f, max=%f}", + this.getClass().getSimpleName(), + getCount(), + getSum(), + getMin(), + getAverage(), + getMax()); + } +}