Annoying behaviour of the != operator

Steven D'Aprano steve at REMOVEMEcyber.com.au
Fri Jun 24 00:19:06 EDT 2005


Max wrote:

> Jordan Rastrick wrote:
>> Well, never, ever use equality or inequality operations with floating
>> point numbers anyway, in any language, as they are notoriously
>> unreliable due to the inherent inaccuracy of floating point. Thats
>> another pitfall, I'll grant, but its a pretty well known one to anyone
>> with programming experience. So I don't think thats a major use case.
> 
> I think this is referring to IEEE 754's NaN equality test, which 
> basically states that x==x is false if-and-only-if x.isNaN() is true.

No. He means exactly what he says: when using floats, 
it is risky to compare one float to another with 
equality, not just NaNs.

This is platform-dependent: I remember the old Standard 
Apple Numerics Environment" (SANE) making the claim 
that testing equality on Macintoshes was safe. And I've 
just spent a fruitless few minutes playing around with 
Python on Solaris trying to find a good example. So it 
is quite possible to work with floats for *ages* before 
being bitten by this.

In general, the problem occurs like this:

Suppose your floating point numbers have six decimal 
digits of accuracy. Then a loop like this may never 
terminate:

x = 1.0/3
while x != 1.0:  # three times one third equals one
     print x
     x += 1.0/3

It will instead print:
0.333333
0.666666
0.999999
1.333332
1.666665
and keep going.

(You can easily see the result yourself with one of 
those cheap-and-nasty calculators with 8 significant 
figures. 1/3*3 is not 1.)

It is a lot harder to find examples on good, modern 
systems with lots of significant figures, but it can 
happen.

Here is a related problem. Adding two floats together 
should never give one of the original numbers unless 
the other one is zero, correct? Then try this:

py> x = 1.0
py> y = 1e-16  # small, but not *that* small
py> y == 0.0
False
py> x+y == x
True
py> x-x+y = x+y-x
False

(Again, platform dependent, your milage may vary.)

Or try the same calculations with x=1e12 and y=1e-6.

In general, the work-around to these floating point 
issues is to avoid floating point in favour of exact 
algebraic calculations whenever possible. If you can't 
avoid floats:

- always sum numbers from smallest to largest;

- never compare equality but always test whether some 
number is within a small amount of your target;

- try to avoid adding or subtracting numbers of wildly 
differing magnitudes; and

- be aware of the risk of errors blowing out and have 
strategies in place to manage the size of the error.


-- 
Steven.




More information about the Python-list mailing list