--- old/src/share/classes/java/util/stream/DoublePipeline.java 2013-11-22 23:03:41.000000000 -0800
+++ new/src/share/classes/java/util/stream/DoublePipeline.java 2013-11-22 23:03:40.000000000 -0800
@@ -377,8 +377,26 @@
@Override
public final double sum() {
- // TODO: better algorithm to compensate for errors
- return reduce(0.0, Double::sum);
+ /*
+ * In the arrays allocated for the collect operation, index 0
+ * holds the high-order bits of the running sum and index 1
+ * holds the low-order bits of the sum computed via
+ * compensated summation.
+ */
+ double[] summation = collect(() -> new double[2],
+ (ll, d) -> {
+ Collectors.sumWithCompensation(ll, d);
+ },
+ // Combine with other compensation
+ // value first for smaller expected
+ // rounding error.
+ (ll, rr) -> {
+ Collectors.sumWithCompensation(ll, rr[1]);
+ Collectors.sumWithCompensation(ll, rr[0]);
+ });
+
+ // Better error bounds to add both terms as the final sum
+ return summation[0] + summation[1];
}
@Override
@@ -391,20 +409,40 @@
return reduce(Math::max);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @implNote The {@code double} format can represent all
+ * consecutive integers in the range -253 to
+ * 253. If the pipeline has more than 253
+ * values, the divisor in the average computation will saturate at
+ * 253, leading to additional numerical errors.
+ */
@Override
public final OptionalDouble average() {
- double[] avg = collect(() -> new double[2],
- (ll, i) -> {
- ll[0]++;
- ll[1] += i;
+ /*
+ * In the arrays allocated for the collect operation, index 0
+ * holds the high-order bits of the running sum, index 1 holds
+ * the low-order bits of the sum computed via compensated
+ * summation, and index 2 holds the number of values seen.
+ */
+ double[] avg = collect(() -> new double[3],
+ (ll, d) -> {
+ ll[2]++;
+ Collectors.sumWithCompensation(ll, d);
},
(ll, rr) -> {
- ll[0] += rr[0];
- ll[1] += rr[1];
+ // Combine with compensation value
+ // first for smaller expected
+ // rounding error.
+ Collectors.sumWithCompensation(ll, rr[1]);
+ Collectors.sumWithCompensation(ll, rr[0]);
+ ll[2] += rr[2];
});
- return avg[0] > 0
- ? OptionalDouble.of(avg[1] / avg[0])
- : OptionalDouble.empty();
+ return avg[2] > 0
+ // Better error bounds to add both terms as the final sum to compute average
+ ? OptionalDouble.of((avg[0] + avg[1]) / avg[2])
+ : OptionalDouble.empty();
}
@Override