classification
Title: round seems to provide floor, not proper rounding
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: lazarillo, r.david.murray, steven.daprano
Priority: normal Keywords:

Created on 2016-10-25 20:41 by lazarillo, last changed 2016-10-25 23:45 by steven.daprano. This issue is now closed.

Files
File name Uploaded Description Edit
bad_tests.py lazarillo, 2016-10-25 20:41 An example of the unittest "assertAlmostEqual" call.
Messages (3)
msg279456 - (view) Author: Mike Williamson (lazarillo) Date: 2016-10-25 20:41
Ran a test that I expected to pass.  When the test failed, I was struck by the strange (incorrect) assertion claim when using unittest.assertAlmostEqual:


AssertionError: 32.78 != 32.775 within 2 places


Uhmm... yes it does!
I delved in, discovering that assertAlmostEquals simply calls round.  So, I tried it with round, shown below:


>>> round(32.775, 2)
32.77
>>> round(32.785, 2)
32.78
>>> round(32.745, 2)
32.74
>>> round(32.746, 2)
32.75


I then looked at the documentation, to understand whether this odd behavior is indeed expected.  I saw (on https://docs.python.org/3/library/functions.html#round ):

---

If two multiples are equally close, rounding is done toward the even choice (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2).

---

However, as you can see, this is not the behavior I'm experiencing. So, it looks like a real bug.

I am attaching the two files where I was running the unit tests, but I'm not sure you really need them.


Thank you!
msg279457 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-10-25 20:58
You must have missed the note about floating point (in the grey box).

assertAlmostEqual is a bit of problem child in any case.  There are open issues about improved functionality for the use case it tries to address.
msg279466 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2016-10-25 23:45
To be clear, let's look at the first failed assertion:

AssertionError: 32.78 != 32.775 within 2 places

It sure *looks* like 32.775 ought to round to 32.78. And indeed it would, if it actually was 32.775. But despite appearances, it isn't. Sure, the number prints as 32.775, but that's a recent feature (and a mixed blessing at that). That's a side-effect of a clever (perhaps too clever) change to the way floats are printed, to prefer neat, friendly numbers over accuracy.

Before Python 2.7, the exact same float would have been printed as 32.774999999999999, and now its obvious why it rounds down to 32.77 rather than up to 32.78: 32.774999999999999 is *less* than 32.775.

To be precise, printing the old way:

32.774999999999999 rounds down to 32.770000000000003 rather than up to 32.780000000000001, exactly as promised.
History
Date User Action Args
2016-10-25 23:45:27steven.dapranosetnosy: + steven.daprano
messages: + msg279466
2016-10-25 20:58:18r.david.murraysetstatus: open -> closed

nosy: + r.david.murray
messages: + msg279457

resolution: not a bug
stage: resolved
2016-10-25 20:41:35lazarillocreate