[Tutor] Fw: About the Round Function

Danny Yoo dyoo at hashcollision.org
Fri Apr 1 21:01:39 EDT 2016


>    My students and I are interested in knowing the rationale behind Python's
>    choice of the Banker's rounding algorithm to be the default rounding
>    algorithm in the third release of Python.

To be specific: your question is on the toplevel round() function.

    https://docs.python.org/3/library/functions.html#round

The assumption implicit in the question is that Python is the only
system that does this.


However, it's not just Python: the general "IEEE 754" standard says to do this.

     https://en.wikipedia.org/wiki/Rounding#Round_half_to_even

There's more background information here:

    http://www.lahey.com/float.htm


---


The rest of this is very-deep diving: if you are a beginner to Python,
I strongly recommend skipping the rest of this.

Let me double check where the rounding is happening, just for my own
peace of mind.

According the source code, in Python 2:

    https://github.com/python-git/python/blob/master/Python/bltinmodule.c#L2064

it does its own thing, and we can see in in terms of floor() and ceiling().


What about in Python 3?

If we look at the latest code,

    http://svn.python.org/projects/python/trunk/Python/bltinmodule.c,

and look for "builtin_round", it tells us to look at the
'_Py_double_round' function defined in floatobject.c,

http://svn.python.org/projects/python/trunk/Objects/floatobject.c

which in fact does appear to have its own implementation of rounding,
with the internal comment C:

/* The basic idea is very simple: convert and round the double to a
       decimal string using _Py_dg_dtoa, then convert that decimal string
       back to a double with _Py_dg_strtod.  There's one minor difficulty:
       Python 2.x expects round to do round-half-away-from-zero, while
       _Py_dg_dtoa does round-half-to-even.  So we need some way to detect
       and correct the halfway cases.

       Detection: a halfway value has the form k * 0.5 * 10**-ndigits for
       some odd integer k.  Or in other words, a rational number x is
       exactly halfway between two multiples of 10**-ndigits if its
       2-valuation is exactly -ndigits-1 and its 5-valuation is at least
       -ndigits.  For ndigits >= 0 the latter condition is automatically
       satisfied for a binary float x, since any such float has
       nonnegative 5-valuation.  For 0 > ndigits >= -22, x needs to be an
       integral multiple of 5**-ndigits; we can check this using fmod.
       For -22 > ndigits, there are no halfway cases: 5**23 takes 54 bits
       to represent exactly, so any odd multiple of 0.5 * 10**n for n >=
       23 takes at least 54 bits of precision to represent exactly.

       Correction: a simple strategy for dealing with halfway cases is to
       (for the halfway cases only) call _Py_dg_dtoa with an argument of
       ndigits+1 instead of ndigits (thus doing an exact conversion to
       decimal), round the resulting string manually, and then convert
       back using _Py_dg_strtod.
    */


Suffice it to say, this is probably too much detail already.


More information about the Tutor mailing list