[Python-Dev] Change in Python 3's "round" behavior
steve at pearwood.info
Sun Sep 30 19:35:30 EDT 2018
On Mon, Oct 01, 2018 at 10:50:36AM +1300, Greg Ewing wrote:
> Alex Walters wrote:
> >Other use case is finance, where you can end up with interest calculations
> >that are fractional of the base unit of currency. US$2.345 is impossible
> >represent in real currency, so it has to be rounded.
> This brings us back to my original point about floating point
> accuracy. If you do your interest calculation in floating
> point binary, first it's very unlikely that it will come
> out ending in exactly 0.5 of a cent,
And yet people (Alex, and he says others) are complaining about this
change in behaviour. If getting exactly 0.5 is as unlikely as you claim,
how would they notice?
> and secondly if you
> care about the details that much, you should be calculating
> in decimal, and being explicit about exactly what kind of
> rounding you're doing.
Why should people using float have a biased round just because "they
should be using Decimal"? The choice to use Decimal is not up to us and
there's nothing wrong with using float for many purposes. Those who do
shouldn't be burdened with a biased round.
Regardless of whether it meets with the approval of the mathematically
naive who think that primary school rounding is the "intuitive" (or
only) way to round, the change was made something like a decade ago. It
matches the behaviour of Julia, .Net, VBScript and I expect other
languages and makes for a technically better default rounding mode.
With no overwhelmingly strong case for reverting to a biased rounding
mode, I think this discussion is dead. If people want to discuss
something more productive, we could talk about adding an optional
argument to round() to take a rounding mode, or adding an equivalent to
the math library.
I'll start off...
How about we move the rounding mode constants out of the decimal module
and into the math module? That makes them more easily discoverable and
importable (the math module is lightweight, the decimal module is not).
The decimal module would then import the constants from math (it already
imports math so that's no extra dependency).
Then we can add a keyword only argument to round:
round(number, ndigits=0, *, mode=ROUND_HALF_EVEN)
To use it, you can import the rounding mode you want from math:
from math import ROUND_CEILING
round(x, 3, mode=ROUND_CEILING)
and everyone is happy (he says optimistically).
It's a bit funny to have constants in the math module not actually used
there, for the benefit of a builtin and Decimal, but I prefer that to
either importing them from decimal or making them builtins.
More information about the Python-Dev