--- old/src/share/classes/java/util/DoubleSummaryStatistics.java 2013-11-22 23:03:39.000000000 -0800 +++ new/src/share/classes/java/util/DoubleSummaryStatistics.java 2013-11-22 23:03:39.000000000 -0800 @@ -63,6 +63,7 @@ public class DoubleSummaryStatistics implements DoubleConsumer { private long count; private double sum; + private double sumCompensation; // Low order bits of sum private double min = Double.POSITIVE_INFINITY; private double max = Double.NEGATIVE_INFINITY; @@ -81,7 +82,7 @@ @Override public void accept(double value) { ++count; - sum += value; + sumWithCompensation(value); min = Math.min(min, value); max = Math.max(max, value); } @@ -95,12 +96,26 @@ */ public void combine(DoubleSummaryStatistics other) { count += other.count; - sum += other.sum; + // Combine with other compensation value first for smaller + // expected rounding error. + sumWithCompensation(other.sumCompensation); + sumWithCompensation(other.sum); min = Math.min(min, other.min); max = Math.max(max, other.max); } /** + * Incorporate a new double value using Kahan summation / + * compensated summation. + */ + private void sumWithCompensation(double value) { + double tmp = value - sumCompensation; + double velvel = sum + tmp; // Little wolf of rounding error + sumCompensation = (velvel - sum) - tmp; + sum = velvel; + } + + /** * Return the count of values recorded. * * @return the count of values @@ -133,7 +148,8 @@ * @return the sum of values, or zero if none */ public final double getSum() { - return sum; + // Better error bounds to add both terms as the final sum + return sum + sumCompensation; } /**