Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How people check nan and inf in C89

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?

like image 443
hukeping Avatar asked Jan 18 '20 03:01

hukeping


2 Answers

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.

like image 82
chux - Reinstate Monica Avatar answered Nov 13 '22 13:11

chux - Reinstate Monica


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).

like image 30
Adrian Mole Avatar answered Nov 13 '22 12:11

Adrian Mole