[Python-Dev] Change in Python 3's "round" behavior

Chris Angelico rosuav at gmail.com
Sun Sep 30 10:14:26 EDT 2018

On Sun, Sep 30, 2018 at 10:18 PM Steven D'Aprano <steve at pearwood.info> wrote:
> On Sat, Sep 29, 2018 at 09:40:03PM -0400, Alex Walters wrote:
> > My experience and that of many users of
> > the python irc channel on freenode is that round-half-to-even is not the
> > intuitive, or even desired, behavior - round-half-up is.
> It would be very informative to ask *why* they want round-half-up.
> I expect that the reason given will boil down to "because it is the
> rounding method I learned in school" even if they can't articulate it
> that way, and start going on about it being "intuitive" as if rounding
> ties upwards was more intuitive than rounding ties downward.

Let's start by assuming that real numbers are a perfectly continuous
space of values, and that every actually-recorded value is *already*
the result of rounding some number to fit within our available space
(rather than assuming that recorded values are perfectly precise and
correct). Further, assume that representable numbers are equally
spaced - not strictly true, but extremely hard to compensate for. That
means that any representable number actually has to indicate a range
of values centered on that value. For the sake of argument, pretend we
can represent one digit before the decimal and one after; in actual
usage, this would occur at the extreme of precision, 53 bits down the

So the number 2.0 actually means the range (1.95, 2.05), the number
2.1 really means (2.05, 2.15), 2.5 means (2.45, 2.55), 2.9 means
(2.85, 2.95), 3.0 means (2.95, 3.05).

Now we take our values and round them to integer.

If we round all 0.5 values up, that means that the rounded value 2
will now catch all values in the range (1.45, 2.45), and the rounded
value 3 catches (2.45, 3.45). In effect, our values are being skewed
low by half a ULP.

By using "round to even", you make the rounded value 2 catch all
values in the range (1.45, 2.55), and the rounded value 3 now catches
(2.55, 3.45). Values are now evenly spread around the stated value,
but there is an entire ULP of discrepancy between the span of even
numbers and the span of odd numbers.

Which is more important? For a number's effective range to be centered
around it, or for its range to be the same size as the range of every
other number?


More information about the Python-Dev mailing list