21

Python3.4 rounds to the nearest even (in the tie-breaker case).

>>> round(1.5)
2
>>> round(2.5)
2

But it only seems to do this when rounding to an integer.

>>> round(2.75, 1)
2.8
>>> round(2.85, 1)
2.9

In the final example above, I would have expected 2.8 as the answer when rounding to the nearest even.

Why is there a discrepancy between the two behaviors?

Air
  • 8,274
  • 2
  • 53
  • 88
Alex Couper
  • 910
  • 9
  • 17
  • 5
    there are so many dupes of this that it almost hurts. – The Paramagnetic Croissant Apr 23 '14 at 15:22
  • 1
    @AirThomas, this is python3 specific in that round() only started rounding to nearest even in python3 AFAIK. – Alex Couper Apr 23 '14 at 15:26
  • @AlexCouper: the even-rounding changed your expectation of what would happen, perhaps, but the differences in what you expected and what you observed are still explained by all those duplicates. – Martijn Pieters Apr 23 '14 at 15:28
  • @user3477950 apologies - at the time of writing I couldn't find any, but following your comment I found http://stackoverflow.com/questions/10825926/python-3-x-rounding-behavior – Alex Couper Apr 23 '14 at 15:28
  • If your question was merely *"Why does this happen in 3.x?"*, the existing answers answer that, but if you actually want to know "How in Python 3.x to get the expected rounding?", then the answer is "use [`decimal` module](https://docs.python.org/3/library/decimal.html)" – smci Nov 13 '19 at 01:49

3 Answers3

33

Floating point numbers are only approximations; 2.85 cannot be represented exactly:

>>> format(2.85, '.53f')
'2.85000000000000008881784197001252323389053344726562500'

It is slightly over 2.85.

0.5 and 0.75 can be represented exactly with binary fractions (1/2 and 1/2 + 1/4, respectively).

The round() function documents this explicitly:

Note: The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

Martijn got it exactly right. If you want an int-rounder to round to the nearest even, then I would go with this:

def myRound(n):
    answer = round(n)
    if not answer%2:
        return answer
    if abs(answer+1-n) < abs(answer-1-n):
        return answer + 1
    else:
        return answer - 1
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
0

To answer the title... If you use int(n), it truncates towards zero. If the result is odd, then you add one:

n = 2.7     # your whatever float
result = int(n)
if (result & 1):     
    result += 1

Update: Yes, there is a bug for negative numbers. And there is also a bug for numbers that already have an integer value. Homework for you. :)

pepr
  • 20,112
  • 15
  • 76
  • 139
  • I don't think this is what the OP wanted. (And this doesn't work for negative numbers, by the way: -1.5 would be 'rounded' to 0.) – Mark Dickinson Apr 25 '14 at 16:58
  • I have never seen someone use `& 1` instead of `% 2` to check whether a number is even before... without the surrounding context, I'm not sure I'd even realize that was what you were doing. I'd assume you were doing some kind of flag comparison or something instead. – ArtOfWarfare Aug 28 '16 at 16:52
  • @MarkDickinson: Thanks for pointing to the bug ;) You are right that Alex had something different in his head. – pepr Aug 29 '16 at 07:08
  • @ArtOfWarfare: I believe that masking the bit is technically less complex (hence faster) than computing the modulo. It is quite common when checking integer for odd/even. As there is no `odd` function in Python, the two are functionally equivalent. Anyway, I would put a short comment to the real code in both cases ;) – pepr Aug 29 '16 at 07:14
  • @pepr They compile to the same thing in languages such as C, and aren't equivalent in overloadable languages such as Python. – wizzwizz4 Jun 11 '17 at 17:36
  • This is definitely not what the OP wanted. He was asking about the Python3 rounding to the nearest even - but that only happens in tie-breaking situations (numbers ending in .5). Other than that, normal rounding rules apply - and I believe that situations in which you would want 2.9 to round to 2 are quite rare... – Bogd Sep 28 '17 at 09:07
  • 1
    @pepr Very nice impl, but you've made a mistake. You wrote it right "If the result is not even", but implemented "if not (result & 1)", ie "if result is not odd". Just remove the "not", and you have a nice 'round to the nearest even' function. – rsalmei Mar 25 '21 at 03:28
  • @rsalmei: You are right. (My English is odd. :) The `(result & 1)` gets the lowest bit. If it is set to one, then the value is odd. – pepr Mar 26 '21 at 12:36