Несовместимость в java.lang. Двойная реализация (Oracle JDK 1.8)? - PullRequest
4 голосов
/ 19 марта 2019

Я посмотрел на реализацию класса 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. Поля неявно устанавливаются в свои значения, но некоторые методы используют явные указанные значения. Есть ли причина этого?

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

1 Ответ

7 голосов
/ 19 марта 2019

В поле 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 Sec 4.2.3 :

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

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

Метод Double.longBitsToDoubleдолжен вернуть a значение, поэтому это значение, которое они решили вернуть.

...