Python2中的math.fsum不准确吗?

5

我正在使用python2 math模块和fsum函数来计算总和。我了解到0.1通常无法以二进制形式存储。据我所知,math.fsum应该可以解决这个问题。

import math
math.fsum([0.0, 0.1])
#0.1
math.fsum([0.1, 0.1])
#0.2
math.fsum([0.2, 0.1])
#0.30000000000000004
math.fsum([0.3, 0.1])
#0.4
math.fsum([0.4, 0.1])
#0.5

那么 math.fsum([0.2, 0.1]) == 0.3 将会是 False。这是正常的吗?我做错了什么吗?

我该如何让 0.2 + 0.1 == 0.3 成为 True 呢?


我认为0.3也不能准确地表示为浮点数。也许使用十进制会更合适? - Wander Nauta
2个回答

10
您误解了math.fsum的功能。它计算给定输入值的最精确可能的总和(即,最接近确切数学总和的可完全表示的值)。它不能用您最初想到的数字魔法般地替换输入。
在上面的第三行中,math.fsum的输入是一个包含值0.10000000000000000555111512312578270211815834045410156250.200000000000000011102230246251565404236316680908203125的列表(请记住,在二进制浮点数中,所看到的并不是所得到的;这里我展示了Python使用的确切值)。这两个值的确切总和是0.3000000000000000166533453693773481063544750213623046875,最接近可以表示为IEEE 754二进制64位浮点数的该确切总和的值是0.3000000000000000444089209850062616169452667236328125,这就是您获得的结果。
您要求math.fsum表现得好像它给出了确切值0.10.2,但是它无法知道这就是您想要的:它只能操作您提供给它的输入。
请注意,在大多数机器上,两个浮点数的加法已经正确地舍入,因此使用math.fsum没有优势。 math.fsum旨在消除汇总两个以上浮点数涉及的舍入误差的累积。

1
实际上,您应该避免使用等号运算符进行浮点数比较。因为计算机以二进制表示它们,并且只能得到浮点数的近似值。
如果您确实需要检查两个浮点数是否相等,则需要定义一个公差:
例如:
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

请参考这个链接:

Python中比较浮点数近似相等的最佳方法是什么?

我发现了这个有趣的网站:

http://0.30000000000000004.com/

在大多数语言中,0.1 + 0.2 不等于 0.3。


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