--- old/src/share/classes/java/util/stream/DoublePipeline.java 2013-11-20 00:17:19.000000000 -0800 +++ new/src/share/classes/java/util/stream/DoublePipeline.java 2013-11-20 00:17:19.000000000 -0800 @@ -377,8 +377,15 @@ @Override public final double sum() { - // TODO: better algorithm to compensate for errors - return reduce(0.0, Double::sum); + double[] summation = collect(() -> new double[2], + (ll, d) -> { + Collectors.sumWithCompensation(ll, d); + }, + (ll, rr) -> { + Collectors.sumWithCompensation(ll, rr[0]); + Collectors.sumWithCompensation(ll, rr[1]); + }); + return summation[0]; } @Override @@ -391,19 +398,29 @@ 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; + double[] avg = collect(() -> new double[3], + (ll, d) -> { + ll[2]++; + Collectors.sumWithCompensation(ll, d); }, (ll, rr) -> { - ll[0] += rr[0]; - ll[1] += rr[1]; + Collectors.sumWithCompensation(ll, rr[0]); + Collectors.sumWithCompensation(ll, rr[1]); + ll[2] += rr[2]; }); return avg[0] > 0 - ? OptionalDouble.of(avg[1] / avg[0]) + ? OptionalDouble.of(avg[0] / avg[2]) : OptionalDouble.empty(); }