[Python-Dev] Round Bug in Python 1.6?

Guido van Rossum guido@python.org
Fri, 07 Apr 2000 15:35:32 -0400


> Tim Peters wrote:
> > The best possible IEEE-754 double approximation to 3.1416 is (exactly)
> > 
> > 3.141599999999999948130380289512686431407928466796875
> 
> Let's call this number 'A' for the sake of discussion.
> 
> > so the output you got is correctly rounded to 17 significant digits.  IOW,
> > it's a feature.
> 
> Clearly there is something very wrong here:
> 
>     Python 1.5.2+ (#2, Mar 28 2000, 18:27:50)
>     Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>     >>> 3.1416
>     3.1415999999999999
>     >>>
> 
> Now you say that 17 significant digits are required to ensure
> that eval(repr(x)) == x, but we surely know that 17 digits are
> *not* required when x is A because i *just typed in* 3.1416 and
> the best choice of double value was A.

Ping has a point!

> I haven't gone and figured it out, but i'll take your word for
> it that 17 digits may be required in *certain* cases to ensure
> that eval(repr(x)) == x.  They're just not required in all cases.
> 
> It's very jarring to type something in, and have the interpreter
> give you back something that looks very different.  It breaks a
> fundamental rule of consistency, and that damages the user's
> trust in the system or their understanding of the system.  (What
> do you do then, start explaining the IEEE double representation
> to your CP4E beginner?)
> 
> What should really happen is that floats intelligently print in
> the shortest and simplest manner possible, i.e. the fewest
> number of digits such that the decimal representation will
> convert back to the actual value.  Now you may say this is a
> pain to implement, but i'm talking about sanity for the user here.
> 
> I haven't investigated how to do this best yet.  I'll go off
> now and see if i can come up with an algorithm that's not
> quite so stupid as
> 
>     def smartrepr(x):
>         p = 17
>         while eval('%%.%df' % (p - 1) % x) == x: p = p - 1
>         return '%%.%df' % p % x

Have a look at what Java does; it seems to be doing this right:

& jpython
JPython 1.1 on java1.2 (JIT: sunwjit)
Copyright (C) 1997-1999 Corporation for National Research Initiatives
>>> import java.lang
>>> x = java.lang.Float(3.1416)
>>> x.toString()
'3.1416'
>>> ^D
& 

Could it be as simple as converting x +/- one bit and seeing how many
differing digits there were?  (Not that +/- one bit is easy to
calculate...)

--Guido van Rossum (home page: http://www.python.org/~guido/)