In C++, is exactly one of <, == and > guaranteed to be true on floats?
Asked Answered
N

1

46

In C++, do I have a guarantee that, for any given float a and float b, one and only one of a < b, a == b and a > b is true?

If this differs between compilers and platforms, I am interested in Visual C++ on x86.

Needs answered 1/2, 2017 at 20:53 Comment(3)
Not if your float is a NaN.Serbocroatian
You probably want to modify this to 'non-NaN float values' to exclude the corner-case?Allanadale
No, at most one of those is guaranteed to be true.Bono
P
75

No.

It's enough for either a or b to be NaN for each of a < b, a == b and a > b to be false.

If both a and b are non-NaN then exactly one of a < b, a == b or a > b has to be true.

In complement, this answer tells you how you can get a NaN value in C++ (there are several NaN values, that can be distinguished by inspecting their representations; they are all different from each other because NaN is never equal to anything,) and how you can test whether a value is a NaN (an idiomatic test to see if a variable x is a NaN is x != x, and indeed std::isnan() is often implemented this way, but some programmers who will have to read your code may be confused by it).

And then, if a and b are the results of previous computations, there is the problem of excess precision. See this article for a discussion in C. The C99 standard solved the problem by making rules explicit for where excess precision could and could not occur, but despite C++ more or less inheriting these rules by deferring to the C standard for the definition of FLT_EVAL_METHOD in cfloat, in practice C compilers take the rules more seriously than C++ compilers. For instance GCC implements the rules for C when compiling with -std=c99, and in this context you can rely on the property to hold, but as of this writing GCC does not implement these rules when used as a C++ compiler.

Pee answered 1/2, 2017 at 20:56 Comment(6)
Will something like 0.0 / 0.0 not get a NaN as well?Unstopped
@JeppeStigNielsen yes, that's a way to write it without relying on any header.Pee
@JeppeStigNielsen: Depending on your FPU settings that might produce an FPU exception instead of a NaN.Fireback
Is the difference of behavior of GCC WRT C and C++ documented anywhere? Is it something related to this?Serration
@Serration Yes, the last part of this answer describes exactly the same problem as the first part as the FAQ entry you linked to. Joseph Myers said when he implemented -fexcess-precision=standard for C that C++ didn't support it yet: gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html . The second part of the FAQ affects how floating-point expressions are computed, so it does not handicap the comparison of lvalues. In any case, with GCC, -ffp-contract=off prevents the issue from the second part of the FAQ.Pee
It's worth pointing the C++ faq about comparisons, which tells the same story: cs.technion.ac.il/users/yechiel/c++-faq/…Til

© 2022 - 2024 — McMap. All rights reserved.