[Tutor] very odd math problem

Steven D'Aprano steve at pearwood.info
Fri Mar 11 06:05:34 CET 2011


Alex Hall wrote:
> Hi all,
> I am trying to get a list of ordered pairs from the below function. In
> my code, evaluate is more exciting, but the evaluate here will at
> least let this run. The below runs fine, with one exception: somehow,
> it is saying that -2+2.0 is 4.x, where x is a huge decimal involving
> E-16 (in other words, a really tiny number). Does anyone have any idea
> what is going on here?


Let's reword the description of the problem...

"2.0 - 2 is a really tiny number close to 4e-16"

Welcome to the wonders of floating point maths! Repeat after me:

     Floats are not real numbers... floats are not real numbers...
     floats are not real numbers... everything you learned about
     arithmetic in school only *approximately* applies to floats.

Half :) and half :(

First off, anything involving e-16 isn't a "huge decimal", it's a tiny 
decimal, very close to zero, no matter what the x is:

0.0000000000000004x

Also, although you say "-2 + 2.0" in a comment, that's not actually what 
you calculate. I know this even though I don't know what you calculate, 
because I can test -2 + 2.0 and see that it is exactly zero:

 >>> -2 + 2.0 == 0
True

Somewhere in your calculation you're probably calculating something 
which *looks* like 2.0 but isn't. Here's an example:

 >>> x = 2 + 1e-14
 >>> print(x)
2.0
 >>> x == 2.0
False

but you can see the difference by printing the float with more decimal 
places than shown by the default view:

 >>> repr(x)
'2.00000000000001'


Another problem: you calculate your values by repeated addition. This is 
the wrong way to do it, because each addition has a tiny little error, 
and repeating them just compounds error upon error. Here's an example:


 >>> x = 0.0
 >>> for i in range(10):
...     x += 0.1
...
 >>> x == 1.0
False
 >>> print(x)
1.0
 >>> repr(x)
'0.99999999999999989'


The right way is to do it like this:


 >>> x = 0.0
 >>> for i in range(1, 11):
...     x = i*0.1
...
 >>> x == 1.0
True

This ensures that errors don't compound.


Some further resources:

http://floating-point-gui.de/
http://introcs.cs.princeton.edu/91float/

David Goldberg used to have a fantastic (although quite technical) 
discussion of floating point issues, "What Every Computer Scientist 
Should Know About Floating-Point Arithmetic":

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Unfortunately, since Oracle bought Sun, they've removed the article. 
Bastards.

If you can find a copy of Apple's old "Apple Numeric Manual" (2nd 
Edition), it has a fantastic introduction by William Kahan. Even though 
the book is about Apple's SANE, a lot will apply to other floating point 
systems as well.

Google on William Kahan and read his stuff :)



-- 
Steven



More information about the Tutor mailing list