I know that floating point addition is not associative: (a + b) + c
in general does not equal a + (b + c)
. So this algorithm for sum can give a different result depending on the order of the input:
float naive_sum(float[] input) {
float accumulator = 0;
for (float x : input) {
accumulator += x;
}
return accumulator;
}
Is it possible to make this order-independent, so that it returns the same result even when the input is shuffled? I'm not trying to reduce the rounding error: I just want it to be order-independent.
One idea is to sort the input first:
float sort_sum(float[] input) {
return naive_sum(sort(input));
}
sort
doesn't have to put the floats in numeric order; it just has to to satisfy sort(input) == sort(shuffle(input))
. I think this works, but it's no longer constant space and linear time the way naive_sum
was.
Another idea is to make the accumulator be a huge integer type: big enough to fit any float without rounding. If floats have an 11-bit exponent, you would need around 2^11 bits, which comes out to around 2000 bits.
float fixedpoint_sum(float[] input) {
int2048 accumulator = 0;
for (float x : input) {
accumulator += float_to_fixed(x);
}
return fixed_to_float(accumulator);
}
Now it's constant space and linear time again, but with such a big accumulator, maybe it's a very slow linear time. :)
Are there any practical algorithms for order-independent summation of floating-point numbers?