如何在Python中解决浮点数列表求和时的精度错误?
在Python3中,0.35 * 10
的结果和把10个0.35
加在一起的结果不一样。
Python 3.8.1 (v3.8.1:1b293b6006, Dec 18 2019, 14:08:53)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.35 * 10
3.5
>>> a = [0.35 for i in range(0, 10)]
>>> sum(a)
3.5000000000000004
有没有办法仅仅通过Python3来解决这个精度问题?也就是说,不使用像numpy这样的库。
1 个回答
5
一种在旧版本的Python中可以使用的方法是用 math.fsum
,如果你正在处理一个包含 float
对象的列表。虽然它的速度比 sum
慢,但准确性相对较高,比如在Python 3.8中:
(py38) jarrivillaga-mbp16-2019:~ jarrivillaga$ python
Python 3.8.18 | packaged by conda-forge | (default, Dec 23 2023, 17:23:49)
[Clang 15.0.7 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [0.35 for i in range(0, 10)]
>>> sum(a)
3.5000000000000004
>>> sum(a) == 0.35*10
False
不过,
>>> import math
>>> math.fsum(a)
3.5
>>> math.fsum(a) == 0.35*10
True
请查看 文档 中的注意事项。
另外,如果你能升级到CPython 3.12,他们实际上改进了内置的 sum
函数:
(py312) jarrivillaga-mbp16-2019:~ jarrivillaga$ python
Python 3.12.1 | packaged by conda-forge | (main, Dec 23 2023, 08:05:03) [Clang 16.0.6 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [0.35 for i in range(0, 10)]
>>> sum(a)
3.5
>>> sum(a) == 0.35*10
True
根据我的理解,numpy.sum
(有时但并不总是)使用的是部分成对求和的方法。
在Python 3.12中,当你处理浮点数时,sum
将使用Arnold Neumaier的补偿求和变体(类似于Kahan方法)。
而 math.fsum
显然更精确,但速度较慢。