If I copy a float to another variable, will they be equal?
I know that using ==
to check equality of floating-point variables is not a good way. But I just want to know that with the following statements:
float x = ...
float y = x;
assert(y == x)
Since y
is copied from x
, will the assertion be true?
Besides the assert(NaN==NaN);
case pointed out by kmdreko, you can have situations with x87-math, when 80bit floats are temporarily stored to memory and later compared to values which are still stored inside a register.
Possible minimal example, which fails with gcc9.2 when compiled with -O2 -m32
:
#include <cassert>
int main(int argc, char**){
float x = 1.f/(argc+2);
volatile float y = x;
assert(x==y);
}
Godbolt Demo: https://godbolt.org/z/X-Xt4R
The volatile
can probably be omitted, if you manage to create sufficient register-pressure to have y
stored and reloaded from memory (but confuse the compiler enough, not to omit the comparison all-together).
See GCC FAQ reference:
- Why floating-point results change with optimization levels or different compiler versions or different target architectures?
It won't be true if x
is NaN
, since comparisons on NaN
are always false (yes, even NaN == NaN
). For all other cases (normal values, subnormal values, infinities, zeros) this assertion will be true.
The advice for avoiding ==
for floats applies to calculations due to floating point numbers being unable to express many results exactly when used in arithmetic expressions. Assignment is not a calculation and there's no reason that assignment would yield a different value than the original.
Extended-precision evaluation should be a non-issue if the standard is followed. From <cfloat>
inherited from C [5.2.4.2.2.8] (emphasis mine):
Except for assignment and cast (which remove all extra range and precision), the values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type.
However, as the comments have pointed out, some cases with certain compilers, build-options, and targets could make this paradoxically false.