Difference between ways to compare floating-point numbers

There seems to be many approaches to judge whether two floating-point numbers are identical. Here are some examples I've found:

1. fabs(x - y) < n * FLT_EPSILON * fabs(x) OR fabs(x - y) < n * FLT_EPSILON * fabs(y)

2. fabs(x - y) < n * FLT_EPSILON * fabs(x + y)

3. fabs(x - y) < n * FLT_EPSILON * fabs(x + y) || fabs(x - y) < FLT_MIN)

4. fabs(x - y) < n * FLT_EPSILON * sqrt(x * x + y * y + FLT_EPSILON * FLT_EPSILON)

I'm really confused about them. Suppose there is a best way to compare two floating-point numbers, which is the simplest as well as the most accurate, the other approaches shouldn't even exist. So these different ways must have there own pros and cons.

My question is: To do "real computations", which approach is the most accurate one?

• Unfortunately, numerical analysis is not a trivial matter, and the correct choice might depend on the sort of calculation that you're doing. – Yuval Filmus Mar 24 '16 at 10:38

You are rightfully confused, because these answers mix up incompatible concepts into a right mess.

If you want to know whether two floating point numbers are equal then you use the "==" operator, which will tell you absolutely correctly whether they are equal.

If you want to know whether they are identical, that's slightly more tricky: There are +0 and -0 which are equal but not identical, and there are NaNs (Not-a-Number) which are not equal, not even equal to themselves, but can be identical.

Now if you perform floating-point arithmetic, then it can happen that two calculations that should have given the same mathematical result do give different results due to rounding errors. It can also happen that two calculations that should have given different mathematical results do give the same result.

There is no quick and easy rule. You need to think about what your goal is, and how to achieve it. And every case is different.

PS. (4) is just awful. Totally, totally wrong. If you use double precision and one of x, y is greater than 10^160, then almost any two numbers will be considered "equal" by this code.

PS. (1-3) are equally awful, because they claim that 0 ≠ 0.

PS. (3) is awful - it completely destroys the idea of gradual underflow.

PS. As a rule, you should use double precision instead of single precision, unless you have a very good reason not to; a reason that you can explain and defend.