Assume two floating point numbers x and y, neither of which are Nan.
Is it safe to assume that equality and inequality tests will:
a. Be consistent with each other:
E.g. is the following guaranteed true:
(x >= y) == ((x > y) || (x == y))
b. Be repeatable
E.g. would (x == y)
always give the same result every time it was evaluated, if neither x nor y have been changed.
I ask this one because of the issue that the floating point unit can store intermediate results to a higher precision that they are stored in memory, and so the value of a variable could possibly change depending on whether it was the result of a recent calculation which is still in the FPU, or whether it has come from memory. Conceivably the first test could be in the former case, and a later test the latter.
As a result, they do not represent all of the same values, are not binary compatible, and have different associated error rates. Because of a lack of guarantees on the specifics of the underlying floating-point system, no assumptions can be made about either precision or range.
This is because floating point values are not precise, and small rounding errors in the floating point operands may cause unexpected results.
It's a problem caused when the internal representation of floating-point numbers, which uses a fixed number of binary digits to represent a decimal number. It is difficult to represent some decimal number in binary, so in many cases, it leads to small roundoff errors.
A float has 23 bits of mantissa, and 2^23 is 8,388,608. 23 bits let you store all 6 digit numbers or lower, and most of the 7 digit numbers. This means that floating point numbers have between 6 and 7 digits of precision, regardless of exponent.
Provided the x
and y
in the question are identifiers (rather than abbreviations for expressions generally, such as x
standing for b + sqrt(c)
), then the C++ standard requires (x >= y) == (x > y || x == y)
to be true.
C++ 2017 (draft N4659) 8 13 allows floating-point expressions to be evaluated with greater precision and range than required by their nominal types. For example, while evaluating an operator with float
operands, the implementation may use double
arithmetic. However, footnote 64 there refers us to 8.4, 8.2.9, and 8.18 to understand that the cast and assignment operators must perform their specific conversions, which produce a value representable in the nominal type.
Thus, once x
and y
have been assigned values, there is no excess precision, and they do not have different values in different uses. Then (x >= y) == (x > y || x == y)
must be true because it is evaluated as it appears and is necessarily mathematically true.
The existence of GCC bug 323 means you cannot rely on GCC when compiling for i386, but this is due to a bug in GCC which violates the C++ standard. Standard C++ does not permit this.
If comparisons are made between expressions, as in:
double y = b + sqrt(c);
if (y != b + sqrt(c))
std::cout << "Unequal\n";
then the value assigned to y
may differ from the value computed for the right operator of b + sqrt(c)
, and the string may be printed, because b + sqrt(c)
may have excess precision, whereas y
must not.
Since casts are also required to remove excess precision, then y != (double) (b + sqrt(c))
should always be false (given the definition of y
above).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With