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.

smci
  • 32,567
  • 20
  • 113
  • 146
MacMillan
  • 593
  • 4
  • 7

1 Answers1

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.

Community
  • 1
  • 1
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • Will something like `0.0 / 0.0` not get __a__ NaN as well? – Jeppe Stig Nielsen Feb 01 '17 at 23:39
  • @JeppeStigNielsen yes, that's a way to write it without relying on any header. – Pascal Cuoq Feb 01 '17 at 23:59
  • 6
    @JeppeStigNielsen: Depending on your FPU settings that might produce an FPU exception instead of a NaN. – Zan Lynx Feb 02 '17 at 01:42
  • Is the difference of behavior of GCC WRT C and C++ documented anywhere? Is it something related to [this](https://gcc.gnu.org/wiki/FAQ#PR323)? – Ruslan Feb 02 '17 at 07:18
  • @Ruslan 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: https://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. – Pascal Cuoq Feb 02 '17 at 09:17
  • It's worth pointing the C++ faq about comparisons, which tells the same story: http://www.cs.technion.ac.il/users/yechiel/c++-faq/floating-point-arith.html – Xavier Nicollet Feb 08 '17 at 23:25