How to overcome a precision error in Python when summing a list of floating point numbers?

73 views Asked by At

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.

1

There are 1 answers

2
juanpa.arrivillaga On BEST ANSWER

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.