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