Is there an isnan() function?
PS.: I\'m in MinGW (if that makes a difference).
I had this solved by using isnan() from
, which doe
On x86-64 you can have extremely fast methods for checking for NaN and infinity, which work regardless of -ffast-math
compiler option. (f != f
, std::isnan
, std::isinf
always yield false
with -ffast-math
).
Testing for NaN, infinity and finite numbers can easily be done by checking for maximum exponent. infinity is maximum exponent with zero mantissa, NaN is maximum exponent and non-zero mantissa. The exponent is stored in the next bits after the topmost sign bit, so that we can just left shift to get rid of the sign bit and make the exponent the topmost bits, no masking (operator&
) is necessary:
static inline uint64_t load_ieee754_rep(double a) {
uint64_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movq instruction.
return r;
}
static inline uint32_t load_ieee754_rep(float a) {
uint32_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movd instruction.
return r;
}
constexpr uint64_t inf_double_shl1 = UINT64_C(0xffe0000000000000);
constexpr uint32_t inf_float_shl1 = UINT32_C(0xff000000);
// The shift left removes the sign bit. The exponent moves into the topmost bits,
// so that plain unsigned comparison is enough.
static inline bool isnan2(double a) { return load_ieee754_rep(a) << 1 > inf_double_shl1; }
static inline bool isinf2(double a) { return load_ieee754_rep(a) << 1 == inf_double_shl1; }
static inline bool isfinite2(double a) { return load_ieee754_rep(a) << 1 < inf_double_shl1; }
static inline bool isnan2(float a) { return load_ieee754_rep(a) << 1 > inf_float_shl1; }
static inline bool isinf2(float a) { return load_ieee754_rep(a) << 1 == inf_float_shl1; }
static inline bool isfinite2(float a) { return load_ieee754_rep(a) << 1 < inf_float_shl1; }
The std
versions of isinf
and isfinite
load 2 double/float
constants from .data
segment and in the worst case scenario they can cause 2 data cache misses. The above versions do not load any data, inf_double_shl1
and inf_float_shl1
constants get encoded as immediate operands into the assembly instructions.
Faster isnan2
is just 2 assembly instructions:
bool isnan2(double a) {
bool r;
asm(".intel_syntax noprefix"
"\n\t ucomisd %1, %1"
"\n\t setp %b0"
"\n\t .att_syntax prefix"
: "=g" (r)
: "x" (a)
: "cc"
);
return r;
}
Uses the fact that ucomisd instruction sets parity flag if any argument is NaN. This is how std::isnan
works when no -ffast-math
options is specified.