[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