Inexact representation cases (Re: Against PEP 240)

Tim Peters tim.one at home.com
Sat Jun 2 16:13:51 EDT 2001


[Clark C . Evans]
> >>> 1.1
> 1.1000000000000001
> >>> 7.35
> 7.3499999999999996
>
> What is the general pattern for these types
> of inexact represenatation?

Unsure what you're looking for.  In general, a non-zero decimal number D is
exactly representable in a binary fp format if and only it can be written in
the form

    D = I/2**J

for some (possibly large) integers I and J, and where the possible values of
I and J are constrained by how many bits the fp format devotes to them.  For
IEEE-754 doubles (which is what a Python float becomes on most machines), it
must have 1 <= I < 2**53 (that is, I has no more than 53 bits), and the
range on J is roughly plus or minus 1000 (yes, it can be made exact, but who
cares <wink>).

So look at 1.1 == 11/10.  Can that be written in the form I/2**J?  If so,
then 11*2**J == 10*I too.  5 divides 10 evenly, so also divides 10*I.  But
if 10*I == 11*2**J and 5 divides the left side, then 5 must also divide the
right side.  But 5 doesn't divide 11 or 2**J, so can't (because 5 is prime)
divide their product evenly either.  IOW, no matter how many bits you use,
1.1 can't be represented exactly in a binary fp format.

It turns out that the closest you can get in IEEE double is

    1.1 ~= 2476979795053773 / 2**51

which is, as a *decimal* number, *exactly*

    1.100000000000000088817841970012523233890533447265625

*Rounding* that to 17 significant decimal digits is where

    1.10000000000000001

comes from in the display.

Similarly the best double approximation to 7.35 is

    4137682157646643 / 2**49

which is exactly

    7.3499999999999996447286321199499070644378662109375

in decimal, which rounds to

    7.3499999999999996

for display.  Note that the situation isn't symmetric:  not every finite
decimal fraction is exactly representable as a finite base 2 fraction, but
every finite binary fraction *is* exactly representable as a finite base 10
fraction (if you start with I/2**J, just multiply top and bottom by 5**J to
get (I*5**J)/10**J).  But afraid that's just another stumbling block at
first ...






More information about the Python-list mailing list