isnan(), isinf()
was not in the spec until C99, is there anyway to implement such a function in C89?
i could use if (d * 0 != 0)
to check if d was NaN or Inf, but we always compile our project with option -Werror=float-equal
which would like to shouting out :error: no == or != on float point value
How people check nan and inf in C89 then?
On review, perhaps another approach for C89.
If we assume comparing a NaN with a finite value is always false (which is the IEEE approach), we could guess that on such systems that do not follow that that the compare is always true (versus sometimes true). The trick would then be to handle both cases.
With x
as a non-Nan, (x >= 0.0) == (x < 0.0)
should always be false as mathematically they are the opposite tests.
With x
as a NaN, if we are fortunate that such x
vs. constant compares are always false or always true, the is_nan()
result is true.
// Assuming -Werror=float-equal
int is_nan(double x) {
return (x >= 0.0) == (x < 0.0);
}
As possible, I would also input a static_assert()
for a C89 compile. Given _Static_assert
does not exist in C89, consider various C89 substitutes as found here.
If your system uses the IEEE 754 Standard to represent floating point values (as most do), then you can explicitly check for the NaN
and inf
values. Single-precision (32-bit) floating-point values have 1
sign bit (bit 31), an 8 bit
exponent (bits 30-23) and a 23 bit
mantissa (bits 22-0), laid out like so (in binary format):
SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM
An infinity value is denoted with an exponent of all 1s and a mantissa of all 0s (the sign bit distinguishes between negative infinity and positive infinity).
A NaN value is denoted by an exponent of all 1s and a non-zero fraction (a quiet NaN has the most significant mantissa bit set, whilst a signalling Nan has this bit clear).
So, by 'casting' the float
to an unsigned, 32-bit integer, we can explicitly check for these representations (assuming unsigned int
is a 32-bit type):
int IsInfinite(float test) {
unsigned int mask = *(unsigned int *)(&test);
return ( (mask & 0x7F800000) == 0x7F800000 && (mask & 0x007FFFFF) == 0 );
}
int NotANumber(float test) {
unsigned int mask = *(unsigned int *)(&test);
return ( (mask & 0x7F800000) == 0x7F800000 && (mask & 0x007FFFFF) != 0 );
}
The representation for double-precision values is similar, but with 11
exponent bits (62-52) and 52
mantissa bits (51-0).
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