Title: Document round half to even rule for floats
Type: behavior Stage:
Components: Documentation Versions: Python 3.8, Python 3.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Francis.Nimick, alexd2, cheryl.sabella, docs@python, eric.smith, mark.dickinson, r.david.murray, terry.reedy
Priority: normal Keywords:

Created on 2013-02-20 21:21 by Francis.Nimick, last changed 2019-04-13 12:29 by cheryl.sabella.

Messages (15)
msg182554 - (view) Author: Francis Nimick (Francis.Nimick) Date: 2013-02-20 21:21
Locale.format() doesn't work correctly with floating point numbers.

locale.format('%.0f', 5.5) -> 6
locale.format('%.0f', 6.5) -> 6
locale.format('%.0f', 7.5) -> 8
locale.format('%.0f', 8.5) -> 8

It seems that if the number before the decimal point is even, it rounds down, else it rounds up.
msg182555 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-02-20 21:27
msg182556 - (view) Author: Francis Nimick (Francis.Nimick) Date: 2013-02-20 21:30
I did end up using round - does that mean the locale.format() behavior is correct?  It's not specified anywhere in the doc that I can find.
msg182560 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2013-02-20 21:58
Perhaps Serhiy meant to direct your attention to the "note" in the round docs.  Floating point is tricky.

In Python3 the round is actually "half to even".  I'm not sure what the rounding algorithm is for %f, but I have a suspicion it might be half to even.  I suppose that it ought to be documented.

Note that this applies equally to regular string formatting, it's not something special about the locale module.
msg182563 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-02-20 22:40
Mark is the ultimate authority here, but my recollection is (and a quick scan of the code shows) that half to even rounding is used in all of our float to string conversions. So that includes %f and float.__format__, among others.
msg182691 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-02-22 19:34
'%.0f' % 5.5, etc, does the same. I agree that consistent 3.x half to even is both correct and and in need of better doc to avoid repeated questions and invalid bug reports.
msg182693 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2013-02-22 20:02
Indeed, in Python 3, round and new-style string formatting both do round-ties-to-even, by design.  Old-style formatting does whatever the underlying OS does, which is typically round-half-away-from-zero.

Python 2 is a bit more of a mess:  in 2.7, new-style formatting does round-ties-to-even, round does round-half-away-from-zero, and old-style formatting continues to do whatever the OS does, just as in Python 3.  And 2.6 is different again (and much more system dependent).

Agreed that this could be better documented for 'format'.  The documentation for the round function is already explicit on this, at least for Python 3.
msg182699 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2013-02-22 20:34
Bah.  Ignore me;  I don't know what I'm talking about.  Old-style formatting does round-half-to-even, too.
msg182706 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2013-02-23 01:39
When I wrote my previous message, I was reading the link above and did not notice that it want to the old 2.7 docs. The 3.x entry is fine.

Perhaps Format Specification Mini-Language could end with
  Rounding of floats is the same as for round().
under the box, with 'round()' linked to its entry.

From what you said, % does half to even on my system only because that is what MC VC10 does. 4.7.2. printf-style String Formatting could add "Rounding is system dependent" as note 6 (currently missing!).

I removed 2.7 because is seems like a mess and mostly does not use the new rule. But from what you say, only round() itself is different. 'Half-away-from-0' could be added, with a note about changing in py 3.
The note for .format would have to give the rule rather than refer to round(). Did I get it all right?
msg182727 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2013-02-23 08:58
I've just looked through the code for 2.7. It uses short float repr for both %-formatting and for float.__format__. So they both use Gay's code, and both should work the same as they do in 3.2+. In all cases, round-half-to-even is used.

It's 2.6 that uses the C library to do float formatting (for both %-formatting and float.__format__).
msg205539 - (view) Author: (alexd2) Date: 2013-12-08 11:01
I encountered the same inconsistent behavior. That is, I don't get the same rounding from the two following commands:

print "%.f %.f" %(0.5, 1.5)               # Gives --> 0 2
print "%.f %.f" %(round(0.5), round(1.5)) # Gives --> 1 2

I also get:
print round(0.5), round(1.5) # Gives --> 1.0 2.0

From what I read in the thread it seems to be more like a bug rather than something to just be documented, right?
msg205560 - (view) Author: (alexd2) Date: 2013-12-08 13:36
I have python2.7.3 in Ubuntu 12.04.3 installed in a VirtualBox VM on a Windows 7 32-bit and an Intel(R) Core(TM)2 Duo CPU U9300 @ 1.20GHz (2 CPUs), ~1.2GHz processor
msg206171 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2013-12-14 08:39
> From what I read in the thread it seems to be more like a bug rather than
> something to just be documented, right?

No, both round and formatting are working as expected: it's just a bit unfortunate that they use different rounding modes in 2.x.  It's not something that it would make sense to change in 2.7 at this stage---any such change would likely break a lot of code.
msg206172 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2013-12-14 08:42
And the Python 2 behaviour has been essentially unchanged for a long time:

Python 2.4.6 (#1, Nov  7 2013, 16:01:20) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "%.f %.f" % (0.5, 1.5)
'0 2'
>>> round(0.5), round(1.5)
(1.0, 2.0)

(Though that first call just shows the result of whatever the OS C libraries decide to do, but historically that seems to be more likely to be round-half-to-even than anything else.)
msg340157 - (view) Author: Cheryl Sabella (cheryl.sabella) * (Python committer) Date: 2019-04-13 12:29
It doesn't seem there have been other bugs reported related to this.  However, if it's still agreed that the documentation should be clarified, I think a link from `locale.format_string()` (note, format() has been deprecated, hence the change in the name) to the Format Specification Mini-Language might helpful.  Also, Terry's suggestion in msg182706 specific to %f rounding could be added.
Date User Action Args
2019-04-13 12:29:46cheryl.sabellasetnosy: + cheryl.sabella

messages: + msg340157
versions: + Python 3.7, Python 3.8, - Python 3.2, Python 3.3, Python 3.4
2013-12-14 08:42:34mark.dickinsonsetmessages: + msg206172
2013-12-14 08:39:27mark.dickinsonsetmessages: + msg206171
2013-12-08 13:36:20alexd2setmessages: + msg205560
2013-12-08 11:01:45alexd2setnosy: + alexd2
messages: + msg205539
2013-02-23 08:58:51eric.smithsetmessages: + msg182727
2013-02-23 01:39:46terry.reedysetmessages: + msg182706
2013-02-22 20:34:45mark.dickinsonsetmessages: + msg182699
2013-02-22 20:02:42mark.dickinsonsetmessages: + msg182693
2013-02-22 19:54:57serhiy.storchakasetnosy: - serhiy.storchaka
2013-02-22 19:34:48terry.reedysetnosy: + terry.reedy
title: locale.format() rounding is not reliable for floats -> Document round half to even rule for floats
messages: + msg182691

versions: - Python 2.7
2013-02-20 22:40:22eric.smithsetmessages: + msg182563
2013-02-20 21:58:01r.david.murraysetversions: + Python 3.2, Python 3.3, Python 3.4
nosy: + eric.smith, r.david.murray, mark.dickinson, docs@python

messages: + msg182560

assignee: docs@python
components: + Documentation, - Library (Lib)
2013-02-20 21:30:05Francis.Nimicksetmessages: + msg182556
2013-02-20 21:27:32serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg182555
2013-02-20 21:21:54Francis.Nimickcreate