10

The documentation for java.lang.Double.NaN says that it is

A constant holding a Not-a-Number (NaN) value of type double. It is equivalent to the value returned by Double.longBitsToDouble(0x7ff8000000000000L).

This seems to imply there are others. If so, how do I get hold of them, and can this be done portably?

To be clear, I would like to find the double values x such that

Double.doubleToRawLongBits(x) != Double.doubleToRawLongBits(Double.NaN)

and

Double.isNaN(x)

are both true.

Kevin J. Chase
  • 3,856
  • 4
  • 21
  • 43
Simon Nickerson
  • 42,159
  • 20
  • 102
  • 127

3 Answers3

12

You need doubleToRawLongBits rather than doubleToLongBits.

doubleToRawLongBits extracts the actual binary representation. doubleToLongBits doesn't, it converts all NaNs to the default NaN first.

double n = Double.longBitsToDouble(0x7ff8000000000000L); // default NaN
double n2 = Double.longBitsToDouble(0x7ff8000000000100L); // also a NaN, but M != 0

System.out.printf("%X\n", Double.doubleToLongBits(n));
System.out.printf("%X\n", Double.doubleToRawLongBits(n));
System.out.printf("%X\n", Double.doubleToLongBits(n2));
System.out.printf("%X\n", Double.doubleToRawLongBits(n2));

output:

7FF8000000000000
7FF8000000000000
7FF8000000000000
7FF8000000000100
finnw
  • 47,861
  • 24
  • 143
  • 221
7

Java uses IEEE 754 for its floating point numbers and therefore follows their rules.

According to the Wikipedia page on NaN it is defined like this:

A bit-wise example of a IEEE floating-point standard single precision NaN: x111 1111 1axx xxxx xxxx xxxx xxxx xxxx where x means don't care.

So there are quite a few bit-patterns all of which are NaN values.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • Thanks. Is this guaranteed to be portable across VMs? – Simon Nickerson Jan 28 '10 at 12:41
  • 1
    @simonn: that question would make me stop for a moment: How exactly do you want to make use of that fact? Do you try to submit in-band information inside the NaN value of a `double`? – Joachim Sauer Jan 28 '10 at 12:44
  • Sort of. I am trying to emulate the semantics of a system where there are several different values which all act like NaN, but they are distinguishable. – Simon Nickerson Jan 28 '10 at 13:34
  • 1
    Just as a side-note: I've since learned that distinguishing different `NaN` values is **not portable** in Java. Some implementations may support it, others may collapse all `NaN` values to a small set of "legit" ones. That may happen at *any* time, *including* simple assignments. – Joachim Sauer Aug 09 '11 at 07:46
3

IEEE 754 defines a NaN as a number with all exponent bits which are 1 and a non zero number in the mantissa.

So for a single-precision number you are looking for:

S     E            M
x  11111111   xxxxxx....xxx (with M != 0)

Java handles this like so:

Double n = Double.longBitsToDouble(0x7ff8000000000000L); // default NaN
Double n2 = Double.longBitsToDouble(0x7ff8000000000100L); // also a NaN, but M != 0

System.out.println(n.isNaN()); // true
System.out.println(n2.isNaN()); // true
System.out.println(n2 != Double.doubleToLongBits(Double.NaN)); // true

To sum, you can use any NaN you want which conforms to the rules aforementioned (all bits 1 in exponent and mantissa != 0).

Yuval Adam
  • 161,610
  • 92
  • 305
  • 395
  • The last statement makes no sense. `Double.doubleToLongBits(...)` is a `long`, which is implicitly converted to `double`, autoboxed and compared by *reference* to `n2`. – finnw Jan 28 '10 at 13:21
  • 1
    Possibly in the last line should be `Double.doubleToLongBits(n2) != Double.doubleToLongBits(Double.NaN)` ? – Simon Nickerson Jan 28 '10 at 13:32
  • That prints `false`, because `doubleToLongBits` converts all `NaN` s to the same value. But it's true if you use `doubleToRawLongBits`. – finnw Jan 28 '10 at 13:51
  • I was wrong about the reference comparison (I just looked at the bytecode.) The `long` is converted to `double`, but `n2` is auto-unboxed and normal `double` comparison is applied. – finnw Jan 28 '10 at 14:01