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