8214761: Bug in parallel Kahan summation implementation

Reviewed-by: darcy
This commit is contained in:
Ian Graves 2021-09-03 00:50:11 +00:00
parent 7fff22afe7
commit dd871819a0
5 changed files with 235 additions and 10 deletions

View file

@ -734,7 +734,8 @@ public final class Collectors {
a[2] += val;},
(a, b) -> { sumWithCompensation(a, b[0]);
a[2] += b[2];
return sumWithCompensation(a, b[1]); },
// Subtract compensation bits
return sumWithCompensation(a, -b[1]); },
a -> computeFinalSum(a),
CH_NOID);
}
@ -765,8 +766,8 @@ public final class Collectors {
* correctly-signed infinity stored in the simple sum.
*/
static double computeFinalSum(double[] summands) {
// Better error bounds to add both terms as the final sum
double tmp = summands[0] + summands[1];
// Final sum with better error bounds subtract second summand as it is negated
double tmp = summands[0] - summands[1];
double simpleSum = summands[summands.length - 1];
if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
return simpleSum;
@ -840,13 +841,19 @@ public final class Collectors {
/*
* 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
* the negated low-order bits of the sum computed via compensated
* summation, and index 2 holds the number of values seen.
*/
return new CollectorImpl<>(
() -> new double[4],
(a, t) -> { double val = mapper.applyAsDouble(t); sumWithCompensation(a, val); a[2]++; a[3]+= val;},
(a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
(a, b) -> {
sumWithCompensation(a, b[0]);
// Subtract compensation bits
sumWithCompensation(a, -b[1]);
a[2] += b[2]; a[3] += b[3];
return a;
},
a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
CH_NOID);
}