I was curious about the implementation and representation of NaN
in both IEEE single- and double-precision floating points, and I found this implementation of an "is NaN" function. Namely:
int isnan(double x)
{
int32_t hx,lx;
// Move lower 32 bits of double to lx, higher 32 to hx.
EXTRACT_WORDS(hx,lx,x);
// Remove sign bit, since -NaN and NaN are both NaN.
hx &= 0x7fffffff;
// Equivalent to hx |= (lx != 0).
hx |= (u_int32_t)(lx|(-lx))>>31;
// Difference is negative iff (hx & 0x7ff00000) == 0x7ff00000 and (hx & 0x000fffff) != 0.
hx = 0x7ff00000 - hx;
return (int)((u_int32_t)(hx))>>31;
}
I didn't understand the purpose of (lx|(-lx)) >> 31
, and after failing to reason it out in my head, I tested it on all integers, and found it results in 0 for lx = 0
and 1 otherwise.
The only reasons I could come up with are that perhaps using (lx != 0)
instead was not possible due to some C standard not defining what integer value is assigned to true operations (e.g. not guaranteed to be 1 for true) or that perhaps !=
is slower than the negative-or-and-bit-shift. Otherwise, I'm stumped.
For reference, the code I used to try all integers, in case of errors.
#include <stdio.h>
#include <stdint.h>
int main(void) {
int32_t i = 0;
do {
if (((uint32_t)(i | (-i)) >> 31) == 0)
printf("%d\n", i); // prints only 0
} while (i++ != 0xFFFFFFFF); // overflows to -max_int and then climb to -1
return 0;
}
lx
and-lx
respectively, and see what you find out from that. – Turkestanlx
or-lx
will be 1 (and thus when you bit-shift 31 right, it'll be 1). My question is why not use(lx != 0)
instead of the comparison. – Lightinghx |= (u_int32_t)(lx != 0)
not work in this case (does not have a conditional jump as far as I can see)? Is a true expression not guaranteed to be converted to an integer value of 1 by some C standard? – Lightingdouble
is aNaN
value. I don't see how it returns anything but 0. It appears to be very old code that has since been replaced - I suspect it's simply several lines of buggy code. – HeratNaN
if the exponent bits are all 1's and the significand/mantissa bits are all 0's. I hit a snag with trying to unravel the mystery of that expression, so I didn't look at the rest of the function too deeply, but my intuition says it should work. Since the lower 32 bits of a double are all part of the significand, I believe the idea is to put a 1 at the end of the higher bit int32 if there are any non-zero bits in the lower bits (thus, the comparison with 0) and then check for any 1s in the significand bits from the upper half. – LightingEXTRACT_WORDS
? – PaisleyNaN == NaN
is false, and perhaps more scary,NaN > x
does not give the same result for!(NaN <= x)
. – Lighting