If I copy a float to another variable, will they be equal?
Yes, y
will assuredly take on the value of x
:
[expr.ass]/2
: In simple assignment (=), the object referred to by the left operand is modified ([defns.access]) by replacing its value with the result of the right operand.
There is no leeway for other values to be assigned.
(Others have already pointed out that an equivalence comparison ==
will nonetheless evaluate to false
for NaN values.)
The usual issue with floating-point ==
is that it's easy to not have quite the value you think you do. Here, we know that the two values, whatever they are, are the same.
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.