47 * <pre> {@code
48 * DoubleSummaryStatistics stats = people.stream()
49 * .collect(Collectors.summarizingDouble(Person::getWeight));
50 *}</pre>
51 *
52 * This computes, in a single pass, the count of people, as well as the minimum,
53 * maximum, sum, and average of their weights.
54 *
55 * @implNote This implementation is not thread safe. However, it is safe to use
56 * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
57 * Collectors.toDoubleStatistics()} on a parallel stream, because the parallel
58 * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
59 * provides the necessary partitioning, isolation, and merging of results for
60 * safe and efficient parallel execution.
61 * @since 1.8
62 */
63 public class DoubleSummaryStatistics implements DoubleConsumer {
64 private long count;
65 private double sum;
66 private double sumCompensation; // Low order bits of sum
67 private double min = Double.POSITIVE_INFINITY;
68 private double max = Double.NEGATIVE_INFINITY;
69
70 /**
71 * Construct an empty instance with zero count, zero sum,
72 * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
73 * max and zero average.
74 */
75 public DoubleSummaryStatistics() { }
76
77 /**
78 * Records another value into the summary information.
79 *
80 * @param value the input value
81 */
82 @Override
83 public void accept(double value) {
84 ++count;
85 sumWithCompensation(value);
86 min = Math.min(min, value);
87 max = Math.max(max, value);
88 }
89
90 /**
91 * Combines the state of another {@code DoubleSummaryStatistics} into this
92 * one.
93 *
94 * @param other another {@code DoubleSummaryStatistics}
95 * @throws NullPointerException if {@code other} is null
96 */
97 public void combine(DoubleSummaryStatistics other) {
98 count += other.count;
99 sumWithCompensation(other.sum);
100 sumWithCompensation(other.sumCompensation);
101 min = Math.min(min, other.min);
102 max = Math.max(max, other.max);
103 }
104
105 /**
106 * Incorporate a new double value using Kahan summation /
107 * compensated summation.
108 */
109 private void sumWithCompensation(double value) {
110 double tmp = value - sumCompensation;
111 double velvel = sum + tmp; // Little wolf of rounding error
112 sumCompensation = (velvel - sum) - tmp;
113 sum = velvel;
114 }
115
116 /**
117 * Return the count of values recorded.
118 *
130 * then the sum will be NaN.
131 *
132 * <p> The value of a floating-point sum is a function both of the
133 * input values as well as the order of addition operations. The
134 * order of addition operations of this method is intentionally
135 * not defined to allow for implementation flexibility to improve
136 * the speed and accuracy of the computed result.
137 *
138 * In particular, this method may be implemented using compensated
139 * summation or other technique to reduce the error bound in the
140 * numerical sum compared to a simple summation of {@code double}
141 * values.
142 *
143 * @apiNote Values sorted by increasing absolute magnitude tend to yield
144 * more accurate results.
145 *
146 * @return the sum of values, or zero if none
147 */
148 public final double getSum() {
149 // Better error bounds to add both terms as the final sum
150 return sum + sumCompensation;
151 }
152
153 /**
154 * Returns the minimum recorded value, {@code Double.NaN} if any recorded
155 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
156 * recorded. Unlike the numerical comparison operators, this method
157 * considers negative zero to be strictly smaller than positive zero.
158 *
159 * @return the minimum recorded value, {@code Double.NaN} if any recorded
160 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
161 * recorded
162 */
163 public final double getMin() {
164 return min;
165 }
166
167 /**
168 * Returns the maximum recorded value, {@code Double.NaN} if any recorded
169 * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
170 * recorded. Unlike the numerical comparison operators, this method
|
47 * <pre> {@code
48 * DoubleSummaryStatistics stats = people.stream()
49 * .collect(Collectors.summarizingDouble(Person::getWeight));
50 *}</pre>
51 *
52 * This computes, in a single pass, the count of people, as well as the minimum,
53 * maximum, sum, and average of their weights.
54 *
55 * @implNote This implementation is not thread safe. However, it is safe to use
56 * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
57 * Collectors.toDoubleStatistics()} on a parallel stream, because the parallel
58 * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
59 * provides the necessary partitioning, isolation, and merging of results for
60 * safe and efficient parallel execution.
61 * @since 1.8
62 */
63 public class DoubleSummaryStatistics implements DoubleConsumer {
64 private long count;
65 private double sum;
66 private double sumCompensation; // Low order bits of sum
67 private double simpleSum; // Used to compute right sum for non-finite inputs
68 private double min = Double.POSITIVE_INFINITY;
69 private double max = Double.NEGATIVE_INFINITY;
70
71 /**
72 * Construct an empty instance with zero count, zero sum,
73 * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
74 * max and zero average.
75 */
76 public DoubleSummaryStatistics() { }
77
78 /**
79 * Records another value into the summary information.
80 *
81 * @param value the input value
82 */
83 @Override
84 public void accept(double value) {
85 ++count;
86 simpleSum += value;
87 sumWithCompensation(value);
88 min = Math.min(min, value);
89 max = Math.max(max, value);
90 }
91
92 /**
93 * Combines the state of another {@code DoubleSummaryStatistics} into this
94 * one.
95 *
96 * @param other another {@code DoubleSummaryStatistics}
97 * @throws NullPointerException if {@code other} is null
98 */
99 public void combine(DoubleSummaryStatistics other) {
100 count += other.count;
101 simpleSum += other.simpleSum;
102 sumWithCompensation(other.sum);
103 sumWithCompensation(other.sumCompensation);
104 min = Math.min(min, other.min);
105 max = Math.max(max, other.max);
106 }
107
108 /**
109 * Incorporate a new double value using Kahan summation /
110 * compensated summation.
111 */
112 private void sumWithCompensation(double value) {
113 double tmp = value - sumCompensation;
114 double velvel = sum + tmp; // Little wolf of rounding error
115 sumCompensation = (velvel - sum) - tmp;
116 sum = velvel;
117 }
118
119 /**
120 * Return the count of values recorded.
121 *
133 * then the sum will be NaN.
134 *
135 * <p> The value of a floating-point sum is a function both of the
136 * input values as well as the order of addition operations. The
137 * order of addition operations of this method is intentionally
138 * not defined to allow for implementation flexibility to improve
139 * the speed and accuracy of the computed result.
140 *
141 * In particular, this method may be implemented using compensated
142 * summation or other technique to reduce the error bound in the
143 * numerical sum compared to a simple summation of {@code double}
144 * values.
145 *
146 * @apiNote Values sorted by increasing absolute magnitude tend to yield
147 * more accurate results.
148 *
149 * @return the sum of values, or zero if none
150 */
151 public final double getSum() {
152 // Better error bounds to add both terms as the final sum
153 double tmp = sum + sumCompensation;
154 if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
155 // If the compensated sum is spuriously NaN from
156 // accumulating one or more same-signed infinite values,
157 // return the correctly-signed infinity stored in
158 // simpleSum.
159 return simpleSum;
160 else
161 return tmp;
162 }
163
164 /**
165 * Returns the minimum recorded value, {@code Double.NaN} if any recorded
166 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
167 * recorded. Unlike the numerical comparison operators, this method
168 * considers negative zero to be strictly smaller than positive zero.
169 *
170 * @return the minimum recorded value, {@code Double.NaN} if any recorded
171 * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
172 * recorded
173 */
174 public final double getMin() {
175 return min;
176 }
177
178 /**
179 * Returns the maximum recorded value, {@code Double.NaN} if any recorded
180 * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
181 * recorded. Unlike the numerical comparison operators, this method
|