1 /*
2 * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
47 *
48 * <pre> {@code
49 * DoubleSummaryStatistics stats = people.stream()
50 * .collect(Collectors.summarizingDouble(Person::getWeight));
51 *}</pre>
52 *
53 * This computes, in a single pass, the count of people, as well as the minimum,
54 * maximum, sum, and average of their weights.
55 *
56 * @implNote This implementation is not thread safe. However, it is safe to use
57 * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
58 * Collectors.summarizingDouble()} on a parallel stream, because the parallel
59 * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
60 * provides the necessary partitioning, isolation, and merging of results for
61 * safe and efficient parallel execution.
62 * @since 1.8
63 */
64 public class DoubleSummaryStatistics implements DoubleConsumer {
65 private long count;
66 private double sum;
67 private double sumCompensation; // Low order bits of sum
68 private double simpleSum; // Used to compute right sum for non-finite inputs
69 private double min = Double.POSITIVE_INFINITY;
70 private double max = Double.NEGATIVE_INFINITY;
71
72 /**
73 * Constructs an empty instance with zero count, zero sum,
74 * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
75 * max and zero average.
76 */
77 public DoubleSummaryStatistics() { }
78
79 /**
80 * Constructs a non-empty instance with the specified {@code count},
81 * {@code min}, {@code max}, and {@code sum}.
82 *
83 * <p>If {@code count} is zero then the remaining arguments are ignored and
84 * an empty instance is constructed.
85 *
86 * <p>If the arguments are inconsistent then an {@code IllegalArgumentException}
87 * is thrown. The necessary consistent argument conditions are:
137 @Override
138 public void accept(double value) {
139 ++count;
140 simpleSum += value;
141 sumWithCompensation(value);
142 min = Math.min(min, value);
143 max = Math.max(max, value);
144 }
145
146 /**
147 * Combines the state of another {@code DoubleSummaryStatistics} into this
148 * one.
149 *
150 * @param other another {@code DoubleSummaryStatistics}
151 * @throws NullPointerException if {@code other} is null
152 */
153 public void combine(DoubleSummaryStatistics other) {
154 count += other.count;
155 simpleSum += other.simpleSum;
156 sumWithCompensation(other.sum);
157 sumWithCompensation(other.sumCompensation);
158 min = Math.min(min, other.min);
159 max = Math.max(max, other.max);
160 }
161
162 /**
163 * Incorporate a new double value using Kahan summation /
164 * compensated summation.
165 */
166 private void sumWithCompensation(double value) {
167 double tmp = value - sumCompensation;
168 double velvel = sum + tmp; // Little wolf of rounding error
169 sumCompensation = (velvel - sum) - tmp;
170 sum = velvel;
171 }
172
173 /**
174 * Return the count of values recorded.
175 *
176 * @return the count of values
177 */
222 *
223 * </ul>
224 *
225 * </ul>
226 *
227 * It is possible for intermediate sums of finite values to
228 * overflow into opposite-signed infinities; if that occurs, the
229 * final sum will be NaN even if the recorded values are all
230 * finite.
231 *
232 * If all the recorded values are zero, the sign of zero is
233 * <em>not</em> guaranteed to be preserved in the final sum.
234 *
235 * @apiNote Values sorted by increasing absolute magnitude tend to yield
236 * more accurate results.
237 *
238 * @return the sum of values, or zero if none
239 */
240 public final double getSum() {
241 // Better error bounds to add both terms as the final sum
242 double tmp = sum + sumCompensation;
243 if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
244 // If the compensated sum is spuriously NaN from
245 // accumulating one or more same-signed infinite values,
246 // return the correctly-signed infinity stored in
247 // simpleSum.
248 return simpleSum;
249 else
250 return tmp;
251 }
252
253 /**
254 * Returns the minimum recorded value, {@code Double.NaN} if any recorded
255 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
256 * recorded. Unlike the numerical comparison operators, this method
257 * considers negative zero to be strictly smaller than positive zero.
258 *
259 * @return the minimum recorded value, {@code Double.NaN} if any recorded
260 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
261 * recorded
262 */
|
1 /*
2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
47 *
48 * <pre> {@code
49 * DoubleSummaryStatistics stats = people.stream()
50 * .collect(Collectors.summarizingDouble(Person::getWeight));
51 *}</pre>
52 *
53 * This computes, in a single pass, the count of people, as well as the minimum,
54 * maximum, sum, and average of their weights.
55 *
56 * @implNote This implementation is not thread safe. However, it is safe to use
57 * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
58 * Collectors.summarizingDouble()} on a parallel stream, because the parallel
59 * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
60 * provides the necessary partitioning, isolation, and merging of results for
61 * safe and efficient parallel execution.
62 * @since 1.8
63 */
64 public class DoubleSummaryStatistics implements DoubleConsumer {
65 private long count;
66 private double sum;
67 private double sumCompensation; // Negative low order bits of sum
68 private double simpleSum; // Used to compute right sum for non-finite inputs
69 private double min = Double.POSITIVE_INFINITY;
70 private double max = Double.NEGATIVE_INFINITY;
71
72 /**
73 * Constructs an empty instance with zero count, zero sum,
74 * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
75 * max and zero average.
76 */
77 public DoubleSummaryStatistics() { }
78
79 /**
80 * Constructs a non-empty instance with the specified {@code count},
81 * {@code min}, {@code max}, and {@code sum}.
82 *
83 * <p>If {@code count} is zero then the remaining arguments are ignored and
84 * an empty instance is constructed.
85 *
86 * <p>If the arguments are inconsistent then an {@code IllegalArgumentException}
87 * is thrown. The necessary consistent argument conditions are:
137 @Override
138 public void accept(double value) {
139 ++count;
140 simpleSum += value;
141 sumWithCompensation(value);
142 min = Math.min(min, value);
143 max = Math.max(max, value);
144 }
145
146 /**
147 * Combines the state of another {@code DoubleSummaryStatistics} into this
148 * one.
149 *
150 * @param other another {@code DoubleSummaryStatistics}
151 * @throws NullPointerException if {@code other} is null
152 */
153 public void combine(DoubleSummaryStatistics other) {
154 count += other.count;
155 simpleSum += other.simpleSum;
156 sumWithCompensation(other.sum);
157 sumWithCompensation(-other.sumCompensation);
158 min = Math.min(min, other.min);
159 max = Math.max(max, other.max);
160 }
161
162 /**
163 * Incorporate a new double value using Kahan summation /
164 * compensated summation.
165 */
166 private void sumWithCompensation(double value) {
167 double tmp = value - sumCompensation;
168 double velvel = sum + tmp; // Little wolf of rounding error
169 sumCompensation = (velvel - sum) - tmp;
170 sum = velvel;
171 }
172
173 /**
174 * Return the count of values recorded.
175 *
176 * @return the count of values
177 */
222 *
223 * </ul>
224 *
225 * </ul>
226 *
227 * It is possible for intermediate sums of finite values to
228 * overflow into opposite-signed infinities; if that occurs, the
229 * final sum will be NaN even if the recorded values are all
230 * finite.
231 *
232 * If all the recorded values are zero, the sign of zero is
233 * <em>not</em> guaranteed to be preserved in the final sum.
234 *
235 * @apiNote Values sorted by increasing absolute magnitude tend to yield
236 * more accurate results.
237 *
238 * @return the sum of values, or zero if none
239 */
240 public final double getSum() {
241 // Better error bounds to add both terms as the final sum
242 double tmp = sum - sumCompensation;
243 if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
244 // If the compensated sum is spuriously NaN from
245 // accumulating one or more same-signed infinite values,
246 // return the correctly-signed infinity stored in
247 // simpleSum.
248 return simpleSum;
249 else
250 return tmp;
251 }
252
253 /**
254 * Returns the minimum recorded value, {@code Double.NaN} if any recorded
255 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
256 * recorded. Unlike the numerical comparison operators, this method
257 * considers negative zero to be strictly smaller than positive zero.
258 *
259 * @return the minimum recorded value, {@code Double.NaN} if any recorded
260 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
261 * recorded
262 */
|