Python浮点数的不正确舍入问题

7
>>> a = 0.3135
>>> print("%.3f" % a)
0.314
>>> a = 0.3125
>>> print("%.3f" % a)
0.312
>>>

我期望得到0.313而不是0.312。你有什么想法,为什么会出现这种情况?是否有其他方法可以使用来获得0.313?

谢谢。


4
搜索"IEEE 754"和"round to even"。舍入并没有错误。它符合标准。 - Bakuriu
5个回答

9

Python 3根据IEEE 754标准进行四舍五入,采用偶数舍入方法。

如果您想以不同的方式进行舍入,则可以手动实现:

import math
def my_round(n, ndigits):
    part = n * 10 ** ndigits
    delta = part - int(part)
    # always round "away from 0"
    if delta >= 0.5 or -0.5 < delta <= 0:
        part = math.ceil(part)
    else:
        part = math.floor(part)
    return part / (10 ** ndigits) if ndigits >= 0 else part * 10 ** abs(ndigits)

使用示例:

In [12]: my_round(0.3125, 3)
Out[12]: 0.313

注意:在Python2中,四舍五入总是远离零,而在Python3中会进行偶数舍入(例如,请参见2.7和3.3之间的round函数文档中的差异)。

失败原因:my_round(4354788000,-9) -> 3999999999.9999995 - Vincent Alex
@VincentAlex 我很确定8年前我写的这段代码假设 ndigits >= 0。无论如何,问题在于你正在触及浮点数限制。如果你检查代码,你会发现在 my_roundreturn 行上,有一个 4 / (10 ** (-9)),它应该返回正确的结果,但实际上并没有。你可以轻松地检查 ndigits 的符号,并对负数情况使用 part * 10 ** abs(ndigits),这似乎效果更好。 - Bakuriu

3

如果你需要精确度不要使用浮点数, 可以使用Decimal

>>> from decimal import *
>>> d = Decimal('0.3125')
>>> getcontext().rounding = ROUND_UP
>>> round(d, 3)
Decimal('0.313')

甚至可以使用分数


0

我遇到了同样的错误舍入问题

round(0.573175, 5) = 0.57317

我的解决方案

def to_round(val, precision=5):
    prec = 10 ** precision
    return str(round(val * prec) / prec)

to_round(0.573175) = '0.57318'

to_round(0.573175) = '0.57318'


0

尝试

print '%.3f' % round(.3125,3)

0

由于round()函数无法正确工作,我使用了LUA方法:

from math import floor
rnd = lambda v, p=0: floor(v*(10**p)+.5)/(10**p)

测试:

>>> round( 128.25, 1 )
128.2
>>> rnd( 128.25, 1 )
128.3
>>>

为了不与其他答案混淆
其他测试包括:

>>> rnd = lambda v, p=0: round(v*(10**p))/(10**p) # hairetdin's answer
>>> rnd( 128.25, 1 )
128.2
>>> print( '%.3f' % round(128.25,1) ) # Tushar's answer
128.200

其他细节:
10**p进行重复处理在性能上几乎可以忽略不计,与存储和引用一个变量相比。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接