I was writing a constexpr bool isfinite(Float)
function because I'm not on C++23 yet and so my std::isfinite
isn't constexpr
. But CI said MSVC didn't like something.
In general, nan should compare false with anything with all comparisons other than !=
which should always be true
: https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN
After some digging, here's the simplest form of the problem:
#include <cassert>
#include <limits>
// Stating assumptions:
static_assert(std::numeric_limits<float>::is_iec559);
static_assert(std::numeric_limits<float>::has_quiet_NaN);
static_assert(std::numeric_limits<float>::has_infinity);
static_assert(std::is_same_v<decltype(NAN), decltype(INFINITY)>);
static_assert(std::is_same_v<float, decltype(INFINITY)>);
int main() {
static_assert(INFINITY == std::numeric_limits<float>::infinity()); // Obviously!
assert(INFINITY == std::numeric_limits<float>::infinity()); // Obviously.
assert(not (NAN < std::numeric_limits<float>::infinity())); // Nan always compares false, so good.
assert(NAN < INFINITY); // What?! This shouldn't pass!
static_assert(NAN < INFINITY); // Neither should this!
static_assert(NAN < std::numeric_limits<float>::infinity()); // Neither should this!
}
https://godbolt.org/z/dsqhcz18E
What the heck is going on? Am I into implementation-defined behavior?
With clang I get the errors I'd expect: https://godbolt.org/z/cvKv8ssax and same with gcc: https://godbolt.org/z/Moen3x1ov
Am I into implementation-defined behavior?
From C++ perspective: Yes, sort of. The non-finite floating point comparisons are not defined by the C++ standard. That said, static_assert(std::numeric_limits<float>::is_iec559)
brings in another standard into consideration.
From IEC 559 aka IEEE-754 perspective: No, the comparisons are defined by this standard, so they aren't implementation defined.
What the heck is going on?
Looks like a bug in the language implementation.