My naive impression is that one would always test the difference against some tolerance epsilon.
Am I wrong? Can testing the equality of floats be meaningful in certain contexts?
There is not a unique recipes.
In this article there is an exhaustive treatment, where you can found a complete answer with technical and code.
In summary, there are mainly 3 cases:
- comparing against zero
- comparing against a non-zero
- comparing two arbitrary numbers
Your idea to use a comparison against a tolerance is good for some cases, but there is also a technic based on Unit in the last place (ULP),
described inside the article
I'm implicit assuming that using the equality operator on floats is indeed meaningful in some contexts; otherwise why would most programming languages allow it.
As above, there are situations where you can use it, but be warned. For example the gcc compiler has a warning:
warning: comparing floating point with == or != is unsafe
Update
I add some considerations above this argument also they are not strictly related to the case a == b
.
Equality with expression
Considering the case:
a + b == c
with a b c
floats. This is what we are coding, but with more pedantic from a math point of view we are doing:
$$
\begin{aligned}
a \oplus b &== c \\
\mathbf{fl}(\mathbf{fl}(a) + \mathbf{fl}(b)) &== \mathbf{fl}(c)\\
\end{aligned}
$$
where
- $\oplus$ machine add
- $\mathbf{fl}(x)$ is the floating point representation of the number $x$, i.e. the real machine number.
With this operation we are introducing a possible estimated error (give the bound) from:
$$
\left| \frac{a}{a+b}\right|\mathit{err}_a +
\left| \frac{b}{a+b}\right|\mathit{err}_b
$$
where
$$\mathit{err}_x = \frac{\lvert x - \mathbf{fl}(x) \rvert}{\lvert x \rvert}$$
So in this case there the use of ==
is more delicate.
Porting in different environments
When we port a code in different environments (different machine) we can obtain some different result (for example try to think to unit test). Also in the case the use of ==
is delicate.