--- 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