Floating point equality [was Re: What exactly is "exact" (was Clean Singleton Docstrings)]

Steven D'Aprano steve at pearwood.info
Wed Jul 20 08:47:14 EDT 2016


On Wed, 20 Jul 2016 05:09 pm, Antoon Pardon wrote:

> Op 20-07-16 om 07:42 schreef Steven D'Aprano:
>> Floating point maths is hard, thinking carefully about what you are doing
>> and whether it is appropriate to use == or a fuzzy almost-equal
>> comparison, or if equality is the right way at all.
>>
>> "But thinking is hard, can't you just tell me the answer?"
>>
>> No. But I can give some guidelines:
>>
>> Floating point arithmetic is deterministic, it doesn't just randomly mix
>> in error out of spite or malice. So in principle, you can always estimate
>> the rounding error from any calculation -- and sometimes there is none.
> 
> I would like to see a practical example of such an outcome.


[steve at ando ~]$ cd /home/steve/python/python-dev/3.4/Lib/test/
[steve at ando test]$ grep self.assertEqual test_statistics.py | wc -l
95


Not all of the 95 examples of using assertEqual apply to float values, but a
good proportion of them do. And if I were a better computer scientist,
there would probably be a lot more assertEquals in my code. A lot of the
time that I do a fuzzy comparison its because I'm too lazy or not good
enough to get a better result.

I am not a good computer scientist. But Bruce Dawson *is* a good computer
scientist:

https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/

Quote:

    Conventional wisdom says that you should never compare two floats
    for equality – you should always use an epsilon. Conventional
    wisdom is wrong.

    I’ve written in great detail about how to compare floating-point
    values using an epsilon, but there are times when it is just not
    appropriate. Sometimes there really is an answer that is correct,
    and in those cases anything less than perfection is just sloppy.

    So yes, I’m proudly comparing floats to see if they are equal.



>> Arithmetic on integer-values (e.g. 1.0) is always exact, up to a limit of
>> either 2**53 or approximately 1e53, I forget which. (That's why most
>> Javascript programmers fail to notice that they don't have an integer
>> type.) So long as you're using operations that only produce integer
>> values from integer arguments (such as + - * // but not / ) then all
>> calculations are exact. It is a waste of time to do:
>>
>> x = 2.0
>> y = x*1002.0
>> is_equal(y, 2004.0, 1e-16)
>>
>> when you can just do y == 2004.0.
> 
> But why perforem integer arithmetics in floats, isn't that a waste of time
> too? I really see no reason to use floats if you know all your results
> will be integers.

In Python, it's probably neither harmful nor useful. The cost of dealing
with boxed values (objects rather than low-level machine values) will
probably outweigh any performance gain one way or the other.

But in lower-level languages, you might find that floating point arithmetic
is faster than integer arithmetic, if you can pass the work on to a FPU
instead of a (slow?) CPU. Or not. It depends on the machine.

Or you might be using a language like Javascript, which intentionally has
only floats for numbers. That's okay, you can still perform exact integer
arithmetic, so long as you stay within the bounds of ±2**16.

Not even in Javascript do you need to write something like this:

x = 0.0
for i in range(20):
    x += 1.0

assert abs(x - 20.0) <= 1e-16




-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list