Monday, March 1, 2010

float comparison and POD equality

I found an interesting discussion on why there is no default comparison operator (operator==) on PODs even though there is a default assignment (operator=). 

operator= can be trivial for PODs as byte=by-byte copy will produce an equivalent result to an element by element copy. Essentially memcpy will work as operator= for PODs. At first you might think that operator== could work the same way, lets just use memcmp.

However theres a spanner in the works - floats cause us some problems. And not in the usual "floating point comparison for numbers that are very close together not showing up as equal" - but something a little more subtle. 

For most floats the bit patterns being equal means the floats are equal and vice versa. However theres a couple of exceptions. -0.0 == 0.0 even though the bit patterns are different. Also NaN != NaN even though the bit patterns are the same.

This means that a bit by bit POD operator== can never work the same way as an element by elememt comparison when floats (or doubles) are in the mix. And that means no default operator==. A sad loss, but maybe a little more understandable to me now.

1 comment:

  1. Things like float comparison (and especially) equality operators have been dangerous since the year dot.

    It's one of those evil things that programmers in Fortran can easily do. (And yes they still exist - a great deal a mathematical and especially weather modelling is still programmed in Fortran). Fortran allows (or certainly used to) things like

    IF (float_variable = 0.0) THEN

    (Or whatever the exact syntax is... you get the point). The above causes all manner of trouble, as does:

    IF (float_variable1 = float_variable2) THEN

    The robust workaround, which seems to be known only by a few, and which also works in other languages / implementations that don't allow the equality test is to define a suitable DELTA that your program (for whatever purpose) permits:

    delta = 0.00001

    (and we know it won't actually be that but it will be close enough) and then use

    if ((float_variable1 - float_variable2) < delta)

    and similarly for the zero test:

    if (float_variable < delta)

    All this does is define something suffiently close to 0 as makes no difference, but it forces us to think about what we are doing rather than have sail on with an assumption that floating point numbers have infinite precision.

    I'm sure this all amounts to teaching you how to suck eggs :)