3

I know that when I would like to check if double == double I should write:

bool AreSame(double a, double b)
{
    return fabs(a - b) < EPSILON;
}

But what when I would like to check if a > b or b > a ?

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
yak
  • 3,770
  • 19
  • 60
  • 111

2 Answers2

11

There is no general solution for comparing floating-point numbers that contain errors from previous operations. The code that must be used is application-specific. So, to get a proper answer, you must describe your situation more specifically. For example, if you are sorting numbers in a list or other data structure, you should not use any tolerance for comparison.

Usually, if your program needs to compare two numbers for order but cannot do so because it has only approximations of those numbers, then you should redesign the program rather than try to allow numbers to be ordered incorrectly.

The underlying problem is that performing a correct computation using incorrect data is in general impossible. If you want to compute some function of two exact mathematical values x and y but the only data you have is some incorrectly computed values x and y, it is generally impossible to compute the exactly correct result. For example, suppose you want to know what the sum, x+y, is, but you only know x is 3 and y is 4, but you do not know what the true, exact x and y are. Then you cannot compute x+y.

If you know that x and y are approximately x and y, then you can compute an approximation of x+y by adding x and y. This works when the function being computed has a reasonable derivative: Slightly changing the inputs of a function with a reasonable derivative slightly changes its outputs. This fails when the function you want to compute has a discontinuity or a large derivative. For example, if you want to compute the square root of x (in the real domain) using an approximation x but x might be negative due to previous rounding errors, then computing sqrt(x) may produce an exception. Similarly, comparing for inequality or order is a discontinuous function: A slight change in inputs can change the answer completely.

The common bad advice is to compare with a “tolerance”. This method trades false negatives (incorrect rejections of numbers that would satisfy the comparison if the true mathematical values were compared) for false positives (incorrect acceptance of numbers that would not satisfy the comparison).

Whether or not an application can tolerate false acceptance depends on the application. Therefore, there is no general solution.

The level of tolerance to set, and even the nature by which it is calculated, depend on the data, the errors, and the previous calculations. So, even when it is acceptable to compare with a tolerance, the amount of tolerance to use and how to calculate it depends on the application. There is no general solution.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

The analogous comparisons are:

a > b - EPSILON

and

b > a - EPSILON

I am assuming that EPSILON is some small positive number.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • +/- epsilon should both be ok. – herohuyongtao Jan 21 '14 at 14:26
  • Sorry for typos. I mean "How can - solve this beyond +?" – herohuyongtao Jan 21 '14 at 14:33
  • 3
    Won't this comparison break when `a` and `b` are exactly equal? `float a = 1; float b = a; (a > b - EPSILON)` would equal `true`, even when `a` is not greater than `b`. – user694733 Jan 21 '14 at 14:35
  • @user694733 That is the whole idea. In exactly the same way that `fabs(a - b) < EPSILON` can evaluate true for `a` and `b` that are not equal. – David Heffernan Jan 21 '14 at 14:50
  • But in that case what is the point of using that epsilon approach over simple `(a >= b)`? – user694733 Jan 21 '14 at 14:56
  • @herohuyongtao I still do not understand. You could write `a + EPSILON > b` instead. Is that what you mean? – David Heffernan Jan 21 '14 at 14:56
  • @user694733 To be tolerant of rounding errors. Same reason why you write `fabs(a - b) < EPSILON`. – David Heffernan Jan 21 '14 at 14:57
  • @DavidHeffernan but you don't want one number to compare greater than another if they are equal, do you? –  Jan 21 '14 at 15:05
  • I understand it in case of `==`, but nature of `>=` is different. It matches *all* values up until certain point. It seems to me that using epsilon with greater/less than -operators will only introduce errors (as demonstrated by my first example). – user694733 Jan 21 '14 at 15:05
  • @H2CO3 Perhaps you should ask the asker. I've sometimes done this when I've been testing for a value being in a particular range. But I think you do have to work pretty hard to come up with a good use case. – David Heffernan Jan 21 '14 at 15:06
  • @DavidHeffernan Yeah, true that. –  Jan 21 '14 at 15:07