Правила, регулирующие сужение двойного до целого
Обратите внимание, что я НЕ ищу код для приведения или сужения двойного к int.
Согласно JLS - $ 5.1.3. Сужение примитивного преобразования
Сужающее преобразование целого числа со знаком в целочисленный тип T просто отбрасывает все, кроме n битов младшего разряда, где n - количество битов, используемых для представления типа T.
Итак, когда я пытаюсь сузить 260 (двоичное представление как 100000100
) к байту, то результат равен 4, потому что младшие 8 бит 00000100
который является десятичным 4 ИЛИ длинное значение 4294967296L (двоичное представление 100000000000000000000000000000000
) к байту, то результатом будет 0.
Теперь, почему я хочу знать правило для сужения правила от двойного до целого, байта и т. Д., Это когда я сужаю double
значение 4294967296.0
тогда результат 2147483647
но когда я сужаю длинный 4294967296L
значение, то результат 0
,
Я понял длинное сужение до int, байтов и т. Д. (Отбрасывает все, кроме n младших битов), но я хочу знать, что происходит под капотами в случае двойного сужения.
3 ответа
Я понял длинное сужение до int, байтов и т. Д. (Отбрасывает все, кроме n младших битов), но я хочу знать, что происходит под капотами в случае двойного сужения.
... Я хочу понять, почему и как часть.
JLS ( JLS 5.1.3) определяет, каков результат. Упрощенная версия (для
int
) является:- NaN становится равным нулю
- Inf становится "max-int" или "min-int"
- иначе:
- округлить до нуля, чтобы получить математическое целое число
- если округленное число слишком велико для
int
, результат становится "min-int" или "max-int"
"Как" зависит от реализации. Для примеров того, как это может быть реализовано, посмотрите на исходный код Hotspot (версия OpenJDK) или заставьте JIT-компилятор вывести некоторый нативный код для просмотра. (Я полагаю, что карты нативного кода используют единственную инструкцию для фактического преобразования.... но я не проверял.)
"Почему" непостижимо... если вы не можете спросить одного из оригинальных разработчиков Java / авторов спецификаций. Правдоподобное объяснение представляет собой сочетание:
- это легко понять
- это согласуется с C / C++,
- это может быть эффективно реализовано на общих аппаратных платформах, и
- это лучше, чем (гипотетические) альтернативы, которые рассматривали дизайнеры.
(Например, создание исключения для NaN, Inf вне допустимого диапазона будет несовместимо с другими примитивными преобразованиями и может быть более дорогим для реализации.)
Когда вы начинаете с двойного значения 4294967296.0, оно больше наибольшего длинного значения, равного 2147483647, поэтому применяется следующее правило (со страницы, на которую вы ссылались): значение должно быть слишком большим (положительное значение большой величины или положительная бесконечность)), и результатом первого шага будет наибольшее представимое значение типа int или long, и вы получите 0x7FFFFFF = 2147483647
Но когда вы пытаетесь преобразовать 4294967296L = 0x100000000, вы начинаете с целочисленного типа, поэтому правило таково: сужающее преобразование целого числа со знаком в целочисленный тип T просто отбрасывает все, кроме n младших битов, поэтому, если n меньше 32 (8 байт) вы просто получите 0.
Результатом является Integer.MAX_VALUE при преобразовании двойного числа в целое, и значение превышает диапазон целого числа. Integer.MAX_VALUE - 2^31 - 1.