Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I do floating point comparison?

I'm currently writing some code where I have something along the lines of:

double a = SomeCalculation1(); double b = SomeCalculation2();  if (a < b)     DoSomething2(); else if (a > b)     DoSomething3(); 

And then in other places I may need to do equality:

double a = SomeCalculation3(); double b = SomeCalculation4();  if (a == 0.0)    DoSomethingUseful(1 / a); if (b == 0.0)    return 0; // or something else here 

In short, I have lots of floating point math going on and I need to do various comparisons for conditions. I can't convert it to integer math because such a thing is meaningless in this context.

I've read before that floating point comparisons can be unreliable, since you can have things like this going on:

double a = 1.0 / 3.0; double b = a + a + a; if ((3 * a) != b)     Console.WriteLine("Oh no!"); 

In short, I'd like to know: How can I reliably compare floating point numbers (less than, greater than, equality)?

The number range I am using is roughly from 10E-14 to 10E6, so I do need to work with small numbers as well as large.

I've tagged this as language agnostic because I'm interested in how I can accomplish this no matter what language I'm using.

like image 724
Mike Bailey Avatar asked Feb 06 '11 19:02

Mike Bailey


People also ask

What are the two approaches used for comparing floating point numbers?

Bitwise comparison. Direct ("exact") IEEE-754 comparison. Absolute margin comparison. Relative epsilon comparison.

Why should we never compare floating point values by using exact equality comparison?

Comparing for equality Simple values like 0.1 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations or the precision of intermediates can change the result.

How do you compare two floating point numbers in Python?

How To Compare Floats in Python. If abs(a - b) is smaller than some percentage of the larger of a or b , then a is considered sufficiently close to b to be "equal" to b . This percentage is called the relative tolerance. You can specify the relative tolerance with the rel_tol keyword argument of math.


1 Answers

Comparing for greater/smaller is not really a problem unless you're working right at the edge of the float/double precision limit.

For a "fuzzy equals" comparison, this (Java code, should be easy to adapt) is what I came up with for The Floating-Point Guide after a lot of work and taking into account lots of criticism:

public static boolean nearlyEqual(float a, float b, float epsilon) {     final float absA = Math.abs(a);     final float absB = Math.abs(b);     final float diff = Math.abs(a - b);      if (a == b) { // shortcut, handles infinities         return true;     } else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {         // a or b is zero or both are extremely close to it         // relative error is less meaningful here         return diff < (epsilon * Float.MIN_NORMAL);     } else { // use relative error         return diff / (absA + absB) < epsilon;     } } 

It comes with a test suite. You should immediately dismiss any solution that doesn't, because it is virtually guaranteed to fail in some edge cases like having one value 0, two very small values opposite of zero, or infinities.

An alternative (see link above for more details) is to convert the floats' bit patterns to integer and accept everything within a fixed integer distance.

In any case, there probably isn't any solution that is perfect for all applications. Ideally, you'd develop/adapt your own with a test suite covering your actual use cases.

like image 169
Michael Borgwardt Avatar answered Sep 20 '22 22:09

Michael Borgwardt