Несоответствие в реализации java.lang.Double (Oracle JDK 1.8)?

Я посмотрел на реализацию класса java.lang.Double. Значение NaN является указанным значением 0x7ff8000000000000L. В поле public static final double NaN установлено значение 0.0d / 0.0, которое должно оцениваться как 0x7ff8000000000000L, если JVM реализует его таким образом.

  1. Почему было выбрано это значение (0x7ff8000000000000L)? Есть ли что-то особенное в этом значении (например, его битовая маска)?

  2. Почему поле неявно установлено на это значение и зависит от базовой реализации операции 0.0d / 0.0, тогда как статический метод public static long doubleToLongBits(double value) явно устанавливает значение 0x7ff8000000000000L для аргумента NaN? Не было ли намного безопаснее неявно установить его, поскольку результат 0.0d / 0.0 сильно зависит от реализации JVM и может быть изменен (скорее всего, никогда не будет) теоретически?

То же самое касается POSITIVE_INFINITY и NEGATIVE_INFINITY. Поля неявно устанавливаются на свои значения, но некоторые методы используют явно заданные значения. Есть ли за этим причина?

Спасибо, что помогаете мне узнавать что-то новое каждый день :-).


person Markus Steppberger    schedule 19.03.2019    source источник
comment
1. Это значение указано в IEEE754.   -  person Andy Turner    schedule 19.03.2019
comment
as the result of 0.0d / 0.0 highly depends on the implementation of the JVM and could be changed - нет, JLS указывает, что 0.d/0.0 возвращает NaN, поэтому 0.d/0.0 по определению является NaN.   -  person Eran    schedule 19.03.2019
comment
Релевантно: Каковы другие значения NaN?   -  person Amadan    schedule 19.03.2019
comment
@AndyTurner: это одно из значений, указанных в IEEE754. Но с таким же успехом подойдет и другой. В частности, NaN не сравнивается с другими числами с плавающей запятой, так как даже одно и то же значение не равно самому себе: Double.NaN == Double.NaN равно false. Но все они вернут true за Double.isNaN.   -  person Amadan    schedule 19.03.2019
comment
Пока спасибо :-). Тем не менее, зачем определять значение как поле, а не использовать его повторно в самом классе, чтобы свести к минимуму избыточность? И я так понимаю, что значение было выбрано случайно и не имеет для него более глубокого значения?   -  person Markus Steppberger    schedule 19.03.2019
comment
Конечно, тот факт, что 0x7ff8000000000000L является длинным, исключает его использование при указании поля с двойным значением.   -  person Andy Turner    schedule 19.03.2019
comment
@ Энди Тернер Хорошо, конечно, я совершенно проглядел это.   -  person Markus Steppberger    schedule 19.03.2019


Ответы (1)


В поле public static final double NaN установлено значение 0.0d / 0.0, которое должно оцениваться как 0x7ff8000000000000L, если JVM реализует его таким образом.

Нет: это приводит к NaN согласно спецификация языка:

Деление нуля на ноль приводит к NaN

0x7ff8000000000000L — это long, а не double, поэтому его нельзя использовать напрямую в качестве инициализатора поля.

В документации Double.NaN указано, что его значение эквивалентно значению, возвращаемому Double.longBitsToDouble(0x7ff8000000000000L). Однако 0.0d / 0.0 используется вместо этого для инициализации поля, потому что это постоянное значение времени компиляции, тогда как вызовы методов — нет.

(Бесстыдная заглушка для мой ответ о том, почему это 0.0d, а не 0.0)


Почему было выбрано это значение (0x7ff8000000000000L)?

Как указано в JLS, раздел 4.2. 3:

IEEE 754 допускает несколько различных значений NaN для каждого из своих одинарных и двойных форматов с плавающей запятой. Хотя каждая аппаратная архитектура возвращает определенный битовый шаблон для NaN при создании нового NaN, программист также может создавать NaN с разными битовыми шаблонами для кодирования, например, ретроспективной диагностической информации.

По большей части платформа Java SE обрабатывает значения NaN данного типа так, как если бы они были свернуты в одно каноническое значение, и, следовательно, эта спецификация обычно относится к произвольному NaN, как к каноническому значению.

Метод Double.longBitsToDouble должен возвращать значение a, так что это значение они выбрали для возврата.

person Andy Turner    schedule 19.03.2019
comment
AFAICS Выбранное значение NaN является наименьшим значением типа long. - person Peter Lawrey; 19.03.2019