[Python-Dev] Backport new float repr to Python 2.7?

Mark Dickinson dickinsm at gmail.com
Sun Oct 11 20:28:11 CEST 2009


In a recent #python-dev IRC conversation, it was suggested that we
should consider backporting the new-style float repr from py3k to
trunk. I'd like to get people's opinions on this idea.
To recap quickly, the algorithm for computing the repr of floats changed
between Python 2.x and Python 3.x (well, actually between 3.0 and 3.1,
but 3.0 is dead):
 - in Python 2.x, repr(x) computes 17 significant decimal digits, and
 then strips trailing zeros. In other words, it's pretty much identical
 to doing '%.17g' % x. The computation is done using the platform's
 *printf functions.
 - in Python 3.x, repr(x) returns the shortest decimal string that's
 guaranteed to evaluate back to the float x under correct rounding.
 The computation is done using David Gay's dtoa.c code, adapted
 for inclusion in Python (in file Python/dtoa.c).
There are (in my view) many benefits to the new approach. Among
them:
 - fewer newbie complaints and questions (on c.l.p, IRC, Stack
 Overflow, etc.) about Python 'rounding incorrectly'. Whether this is a
 good thing or not is the matter of some debate (I'm tempted to
 borrow the time machine and simply say 'see the replies
 to this message'!)
 - string to float *and* float to string conversions are both guaranteed
 correctly rounded in 3.x: David Gay's code implements the conversion
 in both directions, and having correctly rounded string -> float
 conversions is essential to ensure that eval(repr(x)) recovers x exactly.
 - the repr of round(x, n) really does have at most n digits after the
 point, giving the semi-illusion that x really has been rounded exactly,
 and eliminating one of the most common user complaints about the
 round function.
 - round(x, n) agrees exactly with '{:.{}f}'.format(x, n) (this isn't
 true in Python 2.x, and the difference is a cause of bug reports)
 - side effects like finding that float(x) rounds correctly for
 Decimal instances x.
 - the output from the new rule is more consistent: the 'strip trailing
 zeros' part of the old rule has some strange consequences: e.g.,
 in 2.x right now (on a typical machine):
 >>> 0.02
 0.02
 >>> 0.03
 0.029999999999999999
 even though neither 0.02 nor 0.03 can be exactly represented
 in binary. 3.x gives '0.02' and '0.03'.
 - repr(x) is consistent across platforms (or at least across platforms
 with IEEE 754 doubles; in practice this seems to account for
 virtually all platforms currently running Python).
 - the float <-> string conversions are under our control, so any bugs
 found can be fixed in the Python source. There's no shortage of
 conversion bugs in the wild, and certainly bugs have been observed in
 OS X, Linux and Windows. (The ones I found in OS X 10.5 have
 been fixed in OS X 10.6, though.)
Possible problems:
 - breaking docstrings in third party code. Though Eric reminded me
 that when we implemented this for 3.1, there were essentially no
 standard library test breakages resulting from the changed repr
 format.
 - some might argue that the new repr (and round) just allows users
 to remain ignorant of floating-point difficulties for longer, and that
 this is a bad thing. I don't really buy either of these points.
 - someone has to put in the work. As mentioned below, I'm happy
 to do this (and Eric's offered to help, without which this probably
 wouldn't be feasible at all), but it'll use cycles that I could also
 usefully be spending elsewhere.
I'm mostly neutral on the backport idea: I'm very happy that this is
in 3.x, but don't see any great need to backport it. But if there's
majority (+BDFL) support, I'm willing to put the work in to do the
backport.
Masochists who are still reading by this point and who want more
information about the new repr implementation can see the issue
discussion:
http://bugs.python.org/issue1580
Thoughts?
Mark


More information about the Python-Dev mailing list

AltStyle によって変換されたページ (->オリジナル) /