看来默认的 Python
round(1 / 2)
给出 0.
如何将 float 0.5 舍入到 1.0,同时仍然将 0.45 舍入到 0.0,就像通常的学校舍入一样?
目前认为不盲目地将*.5四舍五入是合适的。相反,将 *.5 舍入到最接近的偶数是合适的。 Python 3 实现了这种“适当”形式的“银行家舍入”,但许多其他语言(还)没有。盲目向上舍入 *.5 会产生轻微偏差,但“银行家舍入”有助于平衡它。有关详细信息,请参阅此线程。所以...
方法一
您可以有条件地使用
ceil(...)
函数(来自 math 模块)进行舍入。您必须有条件地执行此操作,以便还保持小于 0.5 的值的常规舍入行为。尝试类似下面的方法(请注意,这不是非常可靠,因为它只适用于正值......不过它应该能够很容易地适应正值和负值):
import math
val = 1.5
x = 0
if (float(val) % 1) >= 0.5:
x = math.ceil(val)
else:
x = round(val)
请注意,
ceil(...)
函数将返回整数,而不是浮点数。这应该不是什么大问题,但现在你知道了。
方法二
从我上面链接的帖子来看,另一种选择似乎是使用 decimal 模块来模拟舍入行为的“旧”方式。我有点从那里复制和粘贴,但是给你:
import decimal
x = decimal.Decimal('1.5').quantize(decimal.Decimal('1'),
rounding=decimal.ROUND_HALF_UP)
据说
decimal.ROUND_HALF_UP
形式的四舍五入就是你要找的。这样你就不必有条件地使用ceil(...)
功能。
获得“学校”舍入,对于介于两者之间的值从 0 开始舍入,对于负数也可以使用下面的函数。这也是 Python 2 中的舍入。
def round_school(x):
i, f = divmod(x, 1)
return int(i + ((f >= 0.5) if (x > 0) else (f > 0.5)))
一些示例结果:
1.50: 2
1.49: 1
0.50: 1
0.49: 0
-0.49: 0
-0.50: -1
-1.49: -1
-1.50: -2
decimal
from decimal import Decimal, ROUND_HALF_UP
def round(number, ndigits=None):
"""Always round off"""
exp = Decimal('1.{}'.format(ndigits * '0')) if ndigits else Decimal('1')
return type(number)(Decimal(number).quantize(exp, ROUND_HALF_UP))
print(round(4.115, 2), type(round(4.115, 2)))
print(round(4.116, 2), type(round(4.116, 2)))
print(round(4.125, 2), type(round(4.125, 2)))
print(round(4.126, 2), type(round(4.126, 2)))
print(round(2.5), type(round(2.5)))
print(round(3.5), type(round(3.5)))
print(round(5), type(round(5)))
print(round(6), type(round(6)))
# 4.12 <class 'float'>
# 4.12 <class 'float'>
# 4.13 <class 'float'>
# 4.13 <class 'float'>
# 3.0 <class 'float'>
# 4.0 <class 'float'>
# 5 <class 'int'>
# 6 <class 'int'>
math
import math
def round(number, ndigits=0):
"""Always round off"""
exp = number * 10 ** ndigits
if abs(exp) - abs(math.floor(exp)) < 0.5:
return type(number)(math.floor(exp) / 10 ** ndigits)
return type(number)(math.ceil(exp) / 10 ** ndigits)
print(round(4.115, 2), type(round(4.115, 2)))
print(round(4.116, 2), type(round(4.116, 2)))
print(round(4.125, 2), type(round(4.125, 2)))
print(round(4.126, 2), type(round(4.126, 2)))
print(round(2.5), type(round(2.5)))
print(round(3.5), type(round(3.5)))
print(round(5), type(round(5)))
print(round(6), type(round(6)))
# 4.12 <class 'float'>
# 4.12 <class 'float'>
# 4.13 <class 'float'>
# 4.13 <class 'float'>
# 3.0 <class 'float'>
# 4.0 <class 'float'>
# 5 <class 'int'>
# 6 <class 'int'>
import math
from timeit import timeit
from decimal import Decimal, ROUND_HALF_UP
def round1(number, ndigits=None):
exp = Decimal('1.{}'.format(ndigits * '0')) if ndigits else Decimal('1')
return type(number)(Decimal(number).quantize(exp, ROUND_HALF_UP))
def round2(number, ndigits=0):
exp = number * 10 ** ndigits
if abs(exp) - abs(math.floor(exp)) < 0.5:
return type(number)(math.floor(exp) / 10 ** ndigits)
return type(number)(math.ceil(exp) / 10 ** ndigits)
print(timeit('round1(123456789.1223456789, 5)', globals=globals()))
print(timeit('round2(123456789.1223456789, 5)', globals=globals()))
# 1.9912803000000001
# 1.2140076999999998
math
一个更快。