10

In Python 2 rounding is done away from 0, so, for example, round(0.5) is 1.0.
In Python 3.x, however, rounding is done toward the even choice, so round(0.5) is 0.
What function can I use in Python 3.x to get the old behavior?

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
planetp
  • 14,248
  • 20
  • 86
  • 160
  • 2
    Do you really want the Python 2 rounding behaviour? The behaviour is pretty complex https://stackoverflow.com/a/22155830/6260170 – Chris_Rands Aug 07 '18 at 12:52
  • You should make clear that you're referring only to rounding of values ending in `.5`. – interjay Aug 07 '18 at 12:54

9 Answers9

8

If your code is not particularly performance sensitive, you can use the standard decimal library to achieve the result you want. Decimal().quantize() allows choosing the rounding method:

from decimal import Decimal, ROUND_HALF_UP
result = float(Decimal(0.5).quantize(Decimal(0), rounding=ROUND_HALF_UP))
print(result)  # Will output 1.0
kristaps
  • 1,705
  • 11
  • 15
4

Equivalent of Python 2.7 round() when rounding to an integer (one-parameter):

import math
def py2round(x):
    if x >= 0.0:
        return math.floor(x + 0.5)
    else:
        return math.ceil(x - 0.5)
AGN Gazer
  • 8,025
  • 2
  • 27
  • 45
1

To get the Python 2 rounding behavior in Python 3 for the one-argument form of round() you can use a custom function like this:

def myround(n):
    if round(n + 1) - round(n) == 1:
        return float(round(n))
    return n + abs(n) / n * 0.5

Demo:

>>> myround(0.5)
1.0
>>> myround(1.5)
2.0
>>> myround(-0.5)
-1.0
>>> myround(-1.5)
-2.0
>>> myround(1)
1.0
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
0
def round_up(x):
    aX = abs(x)
    return math.ceil(aX)*(aX/x)

This solution might work for you.

For x = -1.2 round_up(x) = -2, x = 2.3 round_up(x) = 3 etc.

edit: this solution will crash for x = 0. you can change the return value to

return math.ceil(aX)*(aX/x) if x is not 0 else 0
ozata
  • 542
  • 1
  • 5
  • 16
0

According to CPython source code,

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.

If you care about the performance, consider copying the relevant C code and import as an extension. But if you don't care, here's a Python implementation:

def myround(a):
    num = str(a)
    num = str.split('.', 1)
    if int(num[1][0]) >= 5:
        return int(num[0]) + 1 if a > 0 else int(num[0]) - 1
    else:
        return int(num[0]) - 1 if a > 0 else int(num[0]) + 1
YiFei
  • 1,752
  • 1
  • 18
  • 33
0

Pretty much like the other solutions, but using a shorthand if statement instead of a function:

    segments = ceil(gamma / 90) if gamma > 0 else floor(gamma/90)
Ideogram
  • 1,265
  • 12
  • 21
0

I use this:

f = lambda i:i-i%(1|-(i>0))

print(f('your float number'))

hope be useful!

Sr7
  • 3
  • 4
  • 1
    This looks like it rounds to the nearest infinity, not to the nearest whole like python 2 does it, the question was specifically concerned about the beheaviour with `.5`. You can also provide more context on how exactly the function does the rounding. – Numerlor Feb 04 '22 at 18:44
0

For positive numbers the following works for me:

>>> import math
>>> x = 0.5
>>> (math.trunc(x*2)+1) >> 1
1
Rúben Dias
  • 336
  • 2
  • 9
-1

This is a possible solution I've come up with:

import math

def round_away_from_zero(x):
    a = abs(x)
    r = math.floor(a) + math.floor(2 * (a % 1))
    return r if x >= 0 else -r

Tests:

round_away_from_zero(0.5)
# 1
round_away_from_zero(1.5)
# 2
round_away_from_zero(2.5)
# 3
round_away_from_zero(-0.5)
# -1
round_away_from_zero(-1.5)
# -2
round_away_from_zero(-2.5)
# -3
jdehesa
  • 58,456
  • 7
  • 77
  • 121