[Python-ideas] Way to check for floating point "closeness"?

Steven D'Aprano steve at pearwood.info
Wed Jan 14 11:39:20 CET 2015


On Tue, Jan 13, 2015 at 08:57:38PM -0600, Ron Adam wrote:
> 
> On 01/13/2015 09:53 AM, Chris Barker - NOAA Federal wrote:
[...]
> >I haven't thought it out yet, but maybe we could specify an absolute
> >tolerance near zero, and a relative tolerance elsewhere, both at once.
> >Tricky to document, even if possible.
> 
> Doesn't this problem come up at any boundary comparison, and not just zero?

No.

A quick refresher on error tolerances...

Suppose you have a value which should be exactly 0.5, but you calculate 
it as 0.51. Then the absolute error is 0.51-0.5 = 0.01, and the relative 
error is 0.01/0.5 = 0.02 (or 2%).

But consider two values, 0.0 and 0.1. Then the absolute error is 0.1-0.0 
= 0.1, and the relative error is 0.1/0.0 which is infinite.

So 0.0 and -0.0 are problematic when dealing with relative errors.


> So isn't the issue about any n distance from any floating point number that 
> is less than 1 ulp?  And in that regard, comparison to zero is no different 
> than any comparison to any other floating point value?

No. 1 ULP (Unit In Last Place) is the smallest possible difference 
between two floats. A difference of 0 ULP means the two floats are 
exactly equal.

How it works: in mathematics, real numbers are continuous, but floats 
are not. There are only 2**64 floats in Python (a C double), less if you 
ignore the NANs and INFs, which means we can conveniently enumerate them 
from -(2**64) to (2**64-1), based on the internal structure of a float. 
So if you convert two floats into this enumerated integer value (which 
is equivalent to doing a type-cast from a C double to a C long) and 
subtract the two ints, this gives you a measure of how far apart they 
are. (As Mark mentioned earlier, you have to make allowance for negative 
floats, also INF and NANs are problematic too.)

If two values are exactly equal, their "distance apart" in ULP will be 
zero. A distance of 1 ULP means they are consecutive floats, they cannot 
possibly be any closer without being equal. A distance of 2 ULP means 
there is only a single float separating them, and so on.

Note that ULP do not directly correspond to a numeric tolerance. For 
example, these pairs of values are each 1 ULP apart:

0.0 and 5e-324

1.0 and 1.0000000000000002

1e300 and 1.0000000000000002e+300


So in these three cases, 1 ULP represents numeric differences of:

0.00000000000000000000...00005
0.0000000000000002
2000000000000000000000...000.0

respectively.

 
> Just trying to follow along,

A good resource is Bruce Dawson's blog RandomASCII, if you don't mind 
the focus on C++. Start here:

https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/


-- 
Steve


More information about the Python-ideas mailing list