4

I looked at the implementation of the java.lang.Double class. The value of NaN is the specified value of 0x7ff8000000000000L. The public static final double NaN field is set to 0.0d / 0.0 which should evaluate to 0x7ff8000000000000L if the JVM does implement it that way.

  1. Why was this value (0x7ff8000000000000L) chosen? Is there anything special about that value (e.g. its bit mask)?

  2. Why is the field implicitly set to that value and depends on the underlying implementation of the 0.0d / 0.0 operation whereas the static method public static long doubleToLongBits(double value) sets the value explicitly to 0x7ff8000000000000L for a NaN argument? Wasn't it much safer to implicitly set it as the result of 0.0d / 0.0 highly depends on the implementation of the JVM and could be changed (most likely it never will) theoretically?

The same goes for POSITIVE_INFINITY and NEGATIVE_INFINITY. Fields are implicitly set to their values but some methods use the explicit specified values. Is there a reason behind that?

Thanks for helping me to learn anything new each day :-).

Markus Steppberger
  • 618
  • 1
  • 8
  • 18
  • 2
    1. That is the value specified in IEEE754. – Andy Turner Mar 19 '19 at 07:50
  • 4
    `as the result of 0.0d / 0.0 highly depends on the implementation of the JVM and could be changed` - no, the JLS specifies that 0.d/0.0 returns NaN, so 0.d/0.0 is NaN by definition. – Eran Mar 19 '19 at 07:50
  • 2
    Relevant: [What are the other NaN values?](https://stackoverflow.com/questions/2154484/what-are-the-other-nan-values) – Amadan Mar 19 '19 at 07:51
  • 2
    @AndyTurner: That's _one of the values_ specified in IEEE754. But another would work just as well. In particular, NaN is not compared as other floats, as even the same value is not equal to itself: `Double.NaN == Double.NaN` is `false`. But all of them will return `true` for `Double.isNaN`. – Amadan Mar 19 '19 at 07:52
  • Thanks so far :-). Still, why defining the value as a field and not reusing it in the class itself -> minimizing redundancy? And I do understand that the value was chosen randomly and does not have a "deeper meaning" to it? – Markus Steppberger Mar 19 '19 at 07:55
  • 4
    Surely the fact that `0x7ff8000000000000L` is a long precludes its use in specifying a double-valued field. – Andy Turner Mar 19 '19 at 07:59
  • @Andy Turner Ok sure, I totally overlooked that. – Markus Steppberger Mar 19 '19 at 08:02

1 Answers1

7

The public static final double NaN field is set to 0.0d / 0.0 which should evaluate to 0x7ff8000000000000L if the JVM does implement it that way.

No: it results in NaN, per the language spec:

Division of a zero by a zero results in NaN

0x7ff8000000000000L is a long, not a double, hence that cannot be used as the field initializer directly.

The documentation of Double.NaN does state that its value "is equivalent to the value returned by Double.longBitsToDouble(0x7ff8000000000000L)." However, 0.0d / 0.0 is used in preference to that to initialize the field because it is a compile-time constant value, whereas method invocations are not.

(Shameless plug for my answer about why it is 0.0d, not 0.0)


Why was this value (0x7ff8000000000000L) chosen?

As noted in JLS Sec 4.2.3:

IEEE 754 allows multiple distinct NaN values for each of its single and double floating-point formats. While each hardware architecture returns a particular bit pattern for NaN when a new NaN is generated, a programmer can also create NaNs with different bit patterns to encode, for example, retrospective diagnostic information.

For the most part, the Java SE Platform treats NaN values of a given type as though collapsed into a single canonical value, and hence this specification normally refers to an arbitrary NaN as though to a canonical value.

The Double.longBitsToDouble method has to return a value, so this is the value they chose to return.

Community
  • 1
  • 1
Andy Turner
  • 137,514
  • 11
  • 162
  • 243