views:

95

answers:

3

Let's say I have three 32-bit floating point values, a, b, and c, such that (a + b) + c != a + (b + c). Is there a summation algorithm, perhaps similar to Kahan summation, that guarantees that these values can be summed in any order and always arrive at the exact same (fairly accurate) total? I'm looking for the general case (i.e. not a solution that only deals with 3 numbers).

Is arbitrary precision arithmetic the only way to go? I'm dealing with very large data sets, so I'd like to avoid the overhead of using arbitrary precision arithmetic if possible.

Thanks!

A: 

I am not quite sure that (a + b) + c != a + (b + c) when doing arithmetic in a program.

However the rule of thumb with using floating point arithmetic on present day hardware is to never directly test for equality.

For whatever application you have you should choose an epsilon that is small enough and use

(abs(a - b) < epsilon)

as the equality test.

rep_movsd
@rep_movsd: To see an example where (a + b) + c != a + (b + c), try comparing `(1.0 + 1e20) + -1e20` with `1.0 + (1e20 + -1e20)` in any language that's using IEEE 754 binary64 doubles for its floating-point arithmetic.
Mark Dickinson
@Mark : Yeah I noticed they say that on the wikipedia page, Hadn't come across it myself though.
rep_movsd
@rep_movsd: I'm not actually doing a direct comparison in code. The problem I'm working on is far too complex to describe here, but what I can say is that the lack of associativity in floating-point addition is causing noticeable artifacts the output of a DSP system. Switching to fixed-point would theoretically eliminate these artifacts, but doing so is unfortunately infeasible on this system.
splicer
+5  A: 

There's an interesting 'full-precision-summation' algorithm here, which guarantees that the final sum is independent of the order of the summands (recipe given in Python; but it shouldn't be too difficult to translate to other languages).

It does use a form of arbitrary-precision arithmetic to hold partial sums (the intermediate sums are represented as 'non-overlapping' sums of doubles), but may nevertheless be fast enough, especially when all the inputs are of roughly the same magnitude. And it always gives a correctly rounded result, so accuracy is as good as you could hope for and the final sum is independent of the order of the summands. It's based on this paper (Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates) by Jonathan Shewchuk.

Python uses this algorithm for its implementation of math.fsum, which does correctly-rounded order-independent summation; you can see the C implementation that Python uses here--- look for the math_fsum function.

Mark Dickinson
+1. Python's `math.fsum()` is very well done.
Xavier Ho
Good answer! I've heard of the Shewchuk method before. It seems like it has a lot of overhead though. I was hoping for a solution that uses *O(1)* memory and runs in *O(n)* time. I need to keep adding many billions of floats into a running total throughout the life of my program. Nevertheless, this looks like the best answer so far. I'm going to wait a couple of days before marking it as my accepted answer though, in case someone else comes along with something more efficient ;)
splicer
+1  A: 

With some additional information about the terms you have to sum, you can avoid the overhead of Shewchuk's algorithm.

In IEEE 754 arithmetic, x-y is exact whenever y/2 <= x <= 2*y (Sterbenz theorem, formally proved here)

So if you can arrange all your terms in an order such that each partial sum is of the form above, then you get the exact result for free.

I am afraid that in practice there is little chance of being in conditions where this is assured to happen. Alternating positive and negatives numbers with increasing magnitudes may be one case where it happens.

Note: the original question was about an algorithm that would give the same result regardless of the summation order. Mark's answer initiated a drift in the direction of "an exact algorithm", but reading again your question, I am afraid that I am pushing things too far when I am suggesting to reorder terms. You probably can't in what you are trying to do, and my answer is probably off-topic. Well, sorry :)

Pascal Cuoq
Reordering the terms isn't feasible since the input is an arbitrarily long stream of (essentially) random data. +1 though for introducing me to Sterbenz theorem :)
splicer