I'd like to generate the positive IEEE 754 32-bit float NaN value with integer representation 0x7fc00000 from C89 code.
Here is how I do it with GCC (not conforming to C89):
float mynan(void) { return __builtin_nanf(""); }
Here is how I do it in C89 code (assuming sizeof(int) == 4 or sizeof(long) == 4):
float mynan(void) {
union { float f; unsigned u; unsigned long ul; } fu;
if (sizeof(unsigned) == 4) {
fu.u = 0x7fc00000U;
} else { /* Assume that sizeof(unsigned long) == 4. It's always >=4. */
fu.ul = 0x7fc00000UL;
}
return fu.f;
}
Here is how I test it:
float mynan(void);
typedef char assert_int_size[sizeof(int) == 4 ? 1 : - 1];
int main(int argc, char **argv) {
float f;
union { float f; int i; } fi;
(void)argc; (void)argv;
fi.f = mynan();
printf("0x%x\n", fi.i); /* Prints 0x7fc00000 */
}
My question: is it possible to do it without union (or NAN in <math.h>, which is not C89) or memcpy (or memmove etc.), assuming x87 FPU and a nonoptimizing compiler (e.g. gcc -O0). I want the FPU to generate that NaN value for me as a result of some computation which I can trigger from C89 code.
I tried:
float mynan(void) {
float f = 1L << 30;
f *= f; /* 2 ** 60. */
f *= f; /* 2 ** 120. */
f *= f; /* 2 ** 240, overflows 32-bit float, becomes INFINITY. */
return f * 0.0f; /* NaN. */
}
However, that prints 0xffc00000, which is the corresponding negative NaN value. How do I get the positive one?
I also tried:
float mynan(void) {
float f = 1L << 30;
f *= f; /* 2 ** 60. */
f *= f; /* 2 ** 120. */
f *= f; /* 2 ** 240, overflows 32-bit float, becomes INFINITY. */
return 0.0f - f * 0.0f;
}
This also returns the negative NaN.
I also tried:
float mynan(void) {
float f = 1L << 30;
f *= f; /* 2 ** 60. */
f *= f; /* 2 ** 120. */
f *= f; /* 2 ** 240, overflows 32-bit float, becomes INFINITY. */
return -(f * 0.0f);
}
This works with some compilers (e.g. gcc -O0), but not with others. One of the compilers generates code equivalent to return 0.0f - (f * 0.0f), which keeps the sign as negative.
Try this:
Output from clang, gcc, and Visual C compile and run:
Your mileage may vary.