In Python3, 0.35 * 10
does not show the same result as summing a list of 10 numbers 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
Is it possible to overcome this precision error with Python3 alone? By that I mean without using libraries like numpy.
So, one way to do this that is available on older versions of Python is to use math.fsum
, if you are working with a list of float
objects. It slower than sum
, but it is fairly accurate, so, e.g. with 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
However,
>>> import math
>>> math.fsum(a)
3.5
>>> math.fsum(a) == 0.35*10
True
Please read the caveats in the docs.
Also, if you can just upgrade to CPython 3.12, they actually improved the built-in sum
function:
(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
From what I understand, numpy.sum
(sometimes but not always) uses partial pairwise summation.
In Python 3.12, when you work with floats, sum
will use Arnold Neumaier's variant of compensated summation (a la Kahan).
math.fsum
is apparently even more precise, but slow.