2

As I understand it NaN's are represented by all 1's in the exponent part of a double's representation and non-zero fraction. (Info from here)

Is it safe to test for NaN using something like:

double num = 1.0;

// Do something to make num NaN

double* pointer = #
unsigned long long num2 = *((unsigned long long*)pointer);

if((unsigned long long)num2 == 0x7FF8000000000001)
{
    // Got a NaN
}

I hope that 0x7FF8000000000001 is the correct test.

Since the fraction has to be non-zero to represent a NaN, then I guess the fractional part of the double representation can by anything, so perhaps a more sophisticated test would be required, which converted the fractional part to 1, as shown in the number 0x7FF8000000000001. (Note the 1 on the end, in the fractional part.)

So, would something like this ever be safe to use?

Edit: As Mike mentioned, in the example I should have used a pointer to get the bits, I will make this change now...

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • http://stackoverflow.com/questions/10366485/problems-casting-nan-floats-to-int ? – jcoder Feb 10 '14 at 13:07
  • There are different kinds of NANs, and there is std::isnan... – PlasmaHH Feb 10 '14 at 13:07
  • 3
    That cast does a numeric conversion; you'd need to cast a reference or pointer to reinterpret the bits of the `double` as an integer type. As you say, you'd need to test that that fraction is non-zero, not equal to 1. `std::isnan` will test for NaN correctly and portably; I'd just use that. – Mike Seymour Feb 10 '14 at 13:11
  • 1
    The important part of what Mike mentioned is the use of `std::isnan`. I seen no reason not to use it. – juanchopanza Feb 10 '14 at 13:38
  • Yes, in C++ use `std::isnan( )`, in C use `isnan( )`. – Stephen Canon Feb 10 '14 at 15:39

1 Answers1

3

Quite a few different 64-bit bit patterns mean NaN in floating-point. Mike Seymour told you to use isnan, which is the readable way to check for NaN. You can also use the floating-point comparison x != x, which fails only when x is NaN.

However, if you insist on doing it with bit patterns:

  • The sign bit is irrelevant.
  • The significand mustn't be zero; if it is, you have an infinity rather than a NaN.
  • The biased exponent must be 0x7ff; otherwise, you have a normal or subnormal floating-point number.

So I would suggest, again only if you insist on using bit patterns and tying yourself to your own nonportable code, something like the following ugly, unportable, untested snippet:

u64 xl = (u64 &)x;
u64 sig = xl & 0xfffffffffffffull;
if ((xl >> 52 & 0x7ff) == 0x7ff && sig != 0) return 1;
else return 0;

The high bit of the significand tells you whether you have a "quiet NaN" or a "signaling NaN."

tmyklebu
  • 13,915
  • 3
  • 28
  • 57
  • The test `x != x` should be avoided. Some optimizing compilers will replace `x != x` by `false`. – Johan Råde Sep 13 '14 at 16:53
  • @user763305: Which compilers? Because it sounds like those compilers are broken. – tmyklebu Sep 13 '14 at 16:55
  • I don't remember, but it has happened to me. It also depends on which compiler flags you use. – Johan Råde Sep 13 '14 at 17:22
  • @user763305: Yeah, sometimes you need to work around broken compilers. I can't imagine a compiler that deliberately miscompiles floating-point code in the name of "optimisation" would let very much of my code work, though. You sure you weren't using `-ffast-math` or something like that? – tmyklebu Sep 13 '14 at 17:32
  • I think it was the Intel C++ compiler for Windows with the flag -O3, the highest optimization level. – Johan Råde Sep 13 '14 at 17:58