[Python-Dev] Round Bug in Python 1.6?

Tim Peters tim_one@email.msn.com
Fri, 7 Apr 2000 21:41:48 -0400


[Ka-Ping Yee]
> ,,,
> Now you say that 17 significant digits are required to ensure
> that eval(repr(x)) == x,

Yes.  This was first proved in Jerome Coonen's doctoral dissertation, and is
one of the few things IEEE-754 guarantees about fp I/O:  that
input(output(x)) == x for all finite double x provided that output()
produces at least 17 significant decimal digits (and 17 is minimal).  In
particular, IEEE-754 does *not* guarantee that either I or O are properly
rounded, which latter is needed for what *you* want to see here.  The std
doesn't require proper rounding in this case (despite that it requires it in
all other cases) because no efficient method for doing properly rounded I/O
was known at the time (and, alas, that's still true).

> 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.

Well, x = 1.0 provides a simpler case <wink>.

> 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's in the very nature of binary floating-point that the numbers they type
in are often not the numbers the system uses.

> It breaks a fundamental rule of consistency, and that damages the user's
> trust in the system or their understanding of the system.

If they're surprised by this, they indeed don't understand the arithmetic at
all!  This is an argument for using a different form of arithmetic, not for
lying about reality.

> (What do you do then, start explaining the IEEE double representation
> to your CP4E beginner?)

As above.  repr() shouldn't be used at the interactive prompt anyway (but
note that I did not say str() should be).

> 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.

This can be done, but only if Python does all fp I/O conversions entirely on
its own -- 754-conforming libc routines are inadequate for this purpose
(and, indeed, I don't believe any libc other than Sun's does do proper
rounding here).

For background and code, track down "How To Print Floating-Point Numbers
Accurately" by Steele & White, and its companion paper (s/Print/Read/) by
Clinger.  Steele & White were specifically concerned with printing the
"shortest" fp representation possible such that proper input could later
reconstruct the value exactly.  Steele, White & Clinger give relatively
simple code for this that relies on unbounded int arithmetic.
Excruciatingly difficult and platform-#ifdef'ed "optimized" code for this
was written & refined over several years by the numerical analyst David Gay,
and is available from Netlib.

> 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

This merely exposes accidents in the libc on the specific platform you run
it.  That is, after

    print smartrepr(x)

on IEEE-754 platform A, reading that back in on IEEE-754 platform B may not
yield the same number platform A started with.  Both platforms have to do
proper rounding to make this work; there's no way to do proper rounding by
using libc; so Python has to do it itself; there's no efficient way to do it
regardless; nevertheless, it's a noble goal, and at least a few languages in
the Lisp family require it (most notably Scheme, from whence Steele, White &
Clinger's interest in the subject).

you're-in-over-your-head-before-the-water-touches-your-toes<wink>-ly
    y'rs  - tim