This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: round(float, ndigits<0) sometimes rounds to odd
Type: behavior Stage:
Components: Interpreter Core Versions: Python 3.0, Python 3.1
process
Status: closed Resolution: duplicate
Dependencies: Superseder: Builtin round function is sometimes inaccurate for floats
View: 1869
Assigned To: Nosy List: dingo, mark.dickinson
Priority: normal Keywords:

Created on 2009-03-10 23:18 by dingo, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (5)
msg83450 - (view) Author: Christian Taylor (dingo) Date: 2009-03-10 23:18
round(x, n) may unexpectedly round floats upwards to odd multiples of
10**(-n) if n is negative, depending on the system Python 3 is running
on. I think this is distinct from issue 1869.

Example:
>>> round(25.0, -1)
30.0

I used the following function to check 1000 cases for a given exponent
and yield the values where rounding to odd occurs:

def check(exponent):
    factor = 10**exponent
    for x in range(5, 5+20000, 20):
        if not round(float(x*factor), -1-exponent) < x*factor:
            yield float(x*factor)

On a Core2 Duo running Arch Linux (32bit):
Python 3.1a1+ (py3k:70302, Mar 10 2009, 21:43:09)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> [len(list(check(exponent))) for exponent in range(10)]
[1000, 1000, 1000, 1000, 1000, 0, 0, 1000, 1000, 1000]

On an Athlon XP running Slackware (32bit):
Python 3.1a1+ (py3k:70302, Mar 11 2009, 01:01:18)
[GCC 4.1.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> [len(list(check(exponent))) for exponent in range(10)]
[1000, 1000, 1000, 1000, 1000, 0, 0, 1000, 1000, 1000]

On an Athlon 64 running Debian (32bit):
Python 3.1a1+ (py3k:70302, Mar 10 2009, 22:45:59)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> [len(list(check(exponent))) for exponent in range(10)]
[0, 0, 0, 0, 630, 0, 0, 0, 195, 0]
>>> next(check(4))
650000.0
>>> next(check(8))
14500000000.0
msg83459 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-03-11 08:30
I think this *is* the same issue as 1869, at least in broad terms:  the 
rounding code involves inexact floating-point operations (in this case a 
division by 10.0), which can result in a value that was *exactly* halfway 
between two rounded values losing that exactness, so that the rounding 
direction is essentially random.

Can you tell me why you think this issue is distinct from issue 1869?
msg83463 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-03-11 10:05
> (in this case a division by 10.0)

Of course, that's not true:  division by 10.0 is harmless when the
result is exactly representable.  It's actually a multiplication by
pow(10.0, -1), which is worse...

I'm currently working on incorporating David Gay's code for string <->
float conversions into Python.  If these go in, then it would be
straightforward to implement a fast, correctly-rounded round for floats
based on a combination of Gay's strtod and dtoa functions.
msg83473 - (view) Author: Christian Taylor (dingo) Date: 2009-03-11 16:22
I see what you mean. I originally thought that intermediate numbers not
being representable as floats was not the issue here, since for example
25.0/10.0 should give the exact result - despite issue 1869 clearly
mentioning the *multiplication* by powers of 10.

Thanks for clearing that up and sorry for the noise!
msg83539 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2009-03-13 22:37
Actually the negative n case *is* quite different from the positive n,
although I think it's fair to say that the issue 1869 title covers both 
cases fairly well. :)

It's not at all hard to make sure that round(x, -n) correct for -22 <= -n 
<= 0 and any finite x, using the fact that the remainder fmod(x, 10.0**-n) 
is exactly representable as a float.  I'll try to find time to implement 
this before 3.1.  Positive n is still tricky, though.

Anyway, I'm going to close this and fold the discussion into issue 1869.
Thanks for the report!
History
Date User Action Args
2022-04-11 14:56:46adminsetgithub: 49723
2009-03-13 22:37:29mark.dickinsonsetstatus: pending -> closed

messages: + msg83539
2009-03-11 16:22:27dingosetmessages: + msg83473
2009-03-11 10:05:16mark.dickinsonsetmessages: + msg83463
2009-03-11 08:30:12mark.dickinsonsetstatus: open -> pending

nosy: + mark.dickinson
messages: + msg83459

superseder: Builtin round function is sometimes inaccurate for floats
resolution: duplicate
2009-03-10 23:18:53dingocreate