2010-08-14 2 views
8

Почему приведенный ниже код печатает 2147483647, фактическое значение которого равно 2147483648?Основной вопрос на int int int

i = (int)Math.pow(2,31) ; 
    System.out.println(i); 

Я понимаю, что максимальное положительное значение, что INT может держать это 2147483647. Тогда почему же код, как этот автомобиль оборачивает к отрицательной стороне и печатает -2147483648?

i = (int)Math.pow(2,31) +1 ; 
System.out.println(i); 

i имеет тип Integer. Если второй образец кода (добавление двух целых чисел) может обернуться на отрицательную сторону, если результат выходит за пределы положительного диапазона, почему первый образец не может быть обернут? Кроме того,

i = 2147483648 +1 ; 
System.out.println(i); 

, который очень похож на второй образец кода бросков ошибки на этапе компиляции говоря, что первый буквальным находится вне диапазона целых чисел? Мой вопрос: согласно второму образцу кода, почему первая и третья выборки не могут быть загружены с другой стороны?

+0

Для уточнения это не имеет никакого отношения к 'java.lang.Integer', который отличается от' int'. – polygenelubricants

+1

Как это важно? Проблема (или вопрос) будет одинаковой, даже если я наследую ее (Integer), а не int. – chedine

ответ

12

Для первого образца кода результат сужается от double до int. в файле JLS 5.1.3 описано, как выполняются сужение конверсий для удвоений в int.

Соответствующая часть:

Значение должно быть слишком большим (а положительного значения большой величины или положительной бесконечность), и результат первого шагом является самым большим представимо значением тип int или длинный.

Именно поэтому 2^31 (2147483648) сводится к Integer.MAX_VALUE (2147483647).То же самое верно и для

i = (int)(Math.pow(2,31)+100.0) ; // addition note the parentheses 

и

i = (int)10000000000.0d; // == 2147483647 

Когда добавление делается без скобок, как в вашем втором примере, мы тогда имеем дело с целыми придачу. Для представления значений интегральные типы используют 2's complement. Согласно этой схеме, добавляя 1 к

0x7FFFFFFF (2147483647) 

дает

0x80000000 

что на 2 дополнением для -2147483648. Некоторые языки выполняют проверку переполнения для арифметических операций (например, Ada генерирует исключение). Java, с его наследием C не проверяет переполнение. Процессоры обычно устанавливают overflow flag, когда арифметическая операция переполняется или переполняется. Язык выполнения может проверить этот флаг, хотя это вводит дополнительные накладные расходы, которые некоторые считают ненужными.

Третий пример не компилируется, так как компилятор проверяет значения литерального выражения в отношении диапазона их типа и дает ошибку компилятора для значений вне диапазона. См. JLS 3.10.1 - Integer Literals.

+0

Не '2147483647 = 0x7FFFFFFF' и' -2147483648 = 0x80000000'? – ILMTitan

+0

@ILMTitan - это правильно, и это то, что я думал, что написал, но я вижу, что написал что-то еще. Теперь это исправлено. – mdma

4

Тогда почему код, подобный этому, обертывается на отрицательную сторону и печатает -2147483648?

Это называется переполнение. Java делает это, потому что C делает это. C делает это, потому что это делают большинство процессоров. На некоторых языках этого не происходит. Например, некоторые языки будут генерировать исключение, в других тип изменится на то, что может удерживать результат.

Мой вопрос в том, что касается второго примера кода, почему первая и третья образцы не могут быть обернуты с другой стороны?

Что касается первой программы: Math.pow возвращает двойной и не переполняет. Когда double преобразуется в целое число, он усекается.

Что касается вашей третьей программы: переполнение редко является желательным имуществом и часто является признаком того, что ваша программа больше не работает. Если компилятор может видеть, что он получает переполнение только от оценки константы, которая составляет , почти наверняка - ошибка в коде. Если вы хотите большое отрицательное количество, то почему бы вам написать положительный положительный?

Смежные вопросы