# Why isn't Python king of the hill?

Tim Peters tim.one at home.com
Sun Jun 3 21:23:00 EDT 2001

```[Nick Perkins]
> >>> from math import *
> >>> sqrt(2)**2
> 2.0000000000000004
> >>> sin(pi)
> 1.2246063538223773e-016
>
> Neither of these 'errors' would be eliminated by using Rationals.
> I am sure there are many similar examples.
>
> note that:
> >>> cos(pi)
> -1.0
> actually works, for some reason (luck?)

Floats aren't random -- so luck isn't *really* an issue.  What is an issue
is that the mathematical PI isn't exactly representable as a float (and
binary vs decimal has nothing to do with *this* one), so the machine pi is
really some other number,

pi = PI + tiny

where "tiny" is an error in the last bit (or so) introduced by finite
precision.  Using angle sum formulas,

sin(pi) =
sin(PI+tiny) = cos(tiny)*sin(PI) + sin(tiny)*cos(PI) =
cos(tiny)*0       + sin(tiny)*(-1) =
-sin(tiny) =
[expanding]
-tiny - tiny**3/6 - ...

tiny**3/6 is too small to have any effect when added to tiny (finite
precision again), so the result you see is plain old -tiny.  If you got 0
instead, it would be wrong!  If you carry on the example,

>>> math.sin(math.pi)
1.2246063538223773e-016
>>> math.log(_)/math.log(2)
-52.858531444606918
>>>

you can see the result is about 2**-52, right where "it should be" for a
low-bit error in PI given that floats have 53 bits of precision.

For the other one,

cos(pi) =
cos(PI+tiny) = cos(PI)*cos(tiny) - sin(PI)*sin(tiny) =
(-1)*cos(tiny) -       0*sin(tiny) =
-cos(tiny) =
[expanding]
-1 - tiny**2/2 - ...

Since tiny is about 2**-52, tiny**2/2 is about 2**-105, and that's too small
to have any effect when added to the 53-bit value of -1.0.  So -1.0 on the
nose is what you get.

Of course sin() and cos() aren't actually *implemented* like that, but a
careful implementation will deliver the same result in the end.

```