如何将 float 0.5 舍入到 1.0,同时仍然将 0.45 舍入到 0.0,就像通常的学校舍入一样?

问题描述 投票:0回答:3

看来默认的 Python

round(1 / 2)
给出 0.

如何将 float 0.5 舍入到 1.0,同时仍然将 0.45 舍入到 0.0,就像通常的学校舍入一样?

python python-3.x floating-point rounding
3个回答
13
投票

目前认为盲目地将*.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(...)
功能。


5
投票

获得“学校”舍入,对于介于两者之间的值从 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

0
投票

总是四舍五入

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
一个更快。

© www.soinside.com 2019 - 2024. All rights reserved.