Python 3 rounding behavior in Python 2
python
Solution
Python 3 round in Python 2
The function can look like this:
def py3round(f):
if abs(round(f)-f) == 0.5:
return 2.0*round(f/2.0);
return round(f)
# Python 3 apply round to ... -.1 -.75 -.5 -.25 0 .25 .5 .75 ...
>>> ' '.join(map(str, map(int, [round(i * 0.25) for i in range(-20, 20)])))
'-5 -5 -4 -4 -4 -4 -4 -3 -3 -3 -2 -2 -2 -2 -2 -1 -1 -1 0 0 0 0 0 1 1 1 2 2 2 2 2 3 3 3 4 4 4 4 4 5'
# Python 2 apply round to ... -.1 -.75 -.5 -.25 0 .25 .5 .75 ...
>>> ' '.join(map(str, map(int, [py3round(i * 0.25) for i in range(-20, 20)])))
'-5 -5 -4 -4 -4 -4 -4 -3 -3 -3 -2 -2 -2 -2 -2 -1 -1 -1 0 0 0 0 0 1 1 1 2 2 2 2 2 3 3 3 4 4 4 4 4 5'
Let me clarify what round does in `bltinmodule.c`
if hasattr(args[0], '__round__'):
return args[0].__round__(*args[1:])
else:
raise TypeError("type %.100s doesn't define __round__ method")
So round actually does almost nothing. It depends on the objects passed to it. That leads to `floatobject.c` function `static PyObject *double_round(double x, int ndigits)`
z = round(y);
if (fabs(y-z) == 0.5)
/* halfway between two integers; use round-half-even */
z = 2.0*round(y/2.0);
I used the knowledge of these lines in my function above.
Python 2 round in Python 3
I think you need to write a new function.
def python2round(f):
if round(f + 1) - round(f) != 1:
return f + abs(f) / f * 0.5
return round(f)
The if statement handles the case that `i + 0.5` and `i + 1.5` are rounded into different directions = to even numbers and halves. In this case the rounding is done away from zero.
# in Python 2 apply round to ... -.1 -.75 -.5 -.25 0 .25 .5 .75 ...
>>> ' '.join(map(str, map(int, [round(i * 0.25) for i in range(-20, 20)])))
'-5 -5 -5 -4 -4 -4 -4 -3 -3 -3 -3 -2 -2 -2 -2 -1 -1 -1 -1 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5'
# in Python 3 apply round to ... -.1 -.75 -.5 -.25 0 .25 .5 .75 ...
>>> ' '.join(map(str, map(int, [python2round(i * 0.25) for i in range(-20, 20)])))
'-5 -5 -5 -4 -4 -4 -4 -3 -3 -3 -3 -2 -2 -2 -2 -1 -1 -1 -1 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5'
Do you need a solution with the second argument to round, `ndigits`?
Problem
In Python 2.x, the built-in `round` has the following behavior: if two multiples are equally close, rounding is done away from 0 (so. for example, round(0.5) is 1.0 and round(-0.5) is -1.0) In Python 3.x, this has changed to the more common: 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). Is there an easy way to get this behavior in Python 2.x? Unfortunately, the `future_builtins` module doesn't include this. Maybe there's another similar module I haven't found yet? Or, another way to pull Python 3.x functions into Python 2.x? Obviously, I could write a new function that produces the desired behavior, but I'm more curious if a solution exists that uses the actual Python 3.x function, to avoid adding unnecessary complexity and code to maintain.