Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python2 math.fsum not accurate?

Tags:

python

math

sum

I'm using the python2 math module to calculate sums with fsum. I understand that 0.1 usually can't be stored binary. As far as i understand math.fsum should fix this somehow.

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

So math.fsum([0.2, 0.1]) == 0.3 will be False. Is this supposed to be like this? Am i doing something wrong?

How can i get 0.2 + 0.1 == 0.3 to be True?

like image 551
johnson Avatar asked Jan 07 '16 08:01

johnson


2 Answers

You're misunderstanding what math.fsum does. It computes the most accurate possible sum of the given inputs (that is, the closest exactly representable value to the exact mathematical sum of the inputs). It does not magically replace its inputs with the numbers you originally thought of.

In your third line above, the input to math.fsum is a list containing the values 0.1000000000000000055511151231257827021181583404541015625 and 0.200000000000000011102230246251565404236316680908203125 (remember that with binary floating-point, What You See Is Not What You Get; here I'm showing the exact values that Python's using). The exact sum of those two values is 0.3000000000000000166533453693773481063544750213623046875, and the closest representable IEEE 754 binary64 float to that exact sum is 0.3000000000000000444089209850062616169452667236328125, which is what you're getting.

You're asking for math.fsum to behave as though it were given the exact values 0.1 and 0.2, but it has no way of knowing that that's what you want: it can only operate on the inputs that you give it.

Note that on most machines, addition of two floats will already be correctly rounded, so there's no advantage to using math.fsum. math.fsum is intended to remove the accumulation of rounding error involved in summing more than two floats.

like image 66
Mark Dickinson Avatar answered Oct 01 '22 05:10

Mark Dickinson


Actually, you should avoid to use the equal operator for the float. because computer present them in binary, and only an approximate value of the float.

if you real need to check whether two float is equal, you need to define a tolerance:

For example:

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)

please refer to this:

What is the best way to compare floats for almost-equality in Python?

and I find this funny website:

http://0.30000000000000004.com/

this 0.1 + 0.2 not equals to 0.3 exits in most languages.

like image 39
andrew Avatar answered Oct 01 '22 03:10

andrew