Почему 2 ^ 31 не может храниться в целочисленной переменной, но — 2 ^ 31 может?

#java #c

#java #c

Вопрос:

Целочисленные переменные состоят из 4 байт или 32 бит, а 2 ^ 31 и -2^ 31 в двоичных числах равны 32 битам. Но когда вы помещаете 2 ^ 31 = 2,147,483,648 в целочисленную переменную, она показывает ошибку, но для -2 ^ 31 это нормально. Почему?

введите описание изображения здесь

Комментарии:

1. Потому что вам нужно где-то поместить 0

2. Да, положительный диапазон начинается с 0

3. Подсказка: об этом легче рассуждать с помощью небольших чисел. 8 бит могут хранить от -128 до 127 включительно, в общей сложности 256 значений.

4. Еще один совет: самый значимый (старший) бит — это знаковый бит (в дополнительном обозначении 2). Когда это значение установлено, число становится отрицательным.

Ответ №1:

Целочисленные переменные состоят из 4 байт или 32 бит, а 2 ^ 31 и -2^31 в двоичных числах равны 32 битам

Нет, это не так.

в базовом двоичном коде отрицательные числа не являются чем-то особенным. У нас есть нули и единицы. Там нет знака «нет».

В двоичном 2^31 формате становится:

1000 0000 0000 0000 0000 0000 0000 0000

В двоичном формате -2 ^ 31 не может быть представлено без предварительного определения способа хранения отрицательных чисел.

Обычно (и java делает это тоже) используется система, называемая дополнением 2. дополнение 2 звучит очень сложно: возьмите число, скажем, 5. Представьте его в двоичном формате (для этого упражнения давайте использовать байт, то есть 8 бит): 0000 0101 . Теперь переверните все биты: 1111 1010 , а затем добавьте 1: 1111 1011 .

То есть -5 в двоичном дополнении signed 2.

Эта причудливая система обладает двумя удивительными свойствами: математика продолжает работать в обычном режиме, не требуя знать, подписано число или нет. Давайте попробуем. -5 2 — это -3, верно? давайте посмотрим.. что 1111 1011 такое 0000 0010 ? Я получаю, не беспокоясь о дополнении 2 вообще 1111 1101 . Давайте применим преобразование дополнения 2: сначала переверните биты: 0000 0010 , затем добавьте 1: 0000 0011 , что равно … 3. Так -5 2 что -3. Проверьте. Другим удивительным свойством является то, что он не «тратит» 2 2^32 «слота» на нули. Давайте попробуем дополнить 2 0: 0000 0000 , затем перевернем все биты: 1111 1111 , затем добавим 1: 0000 0000 (с битовым переполнением, которое мы игнорируем). Это хорошо: 0 — это его собственное дополнение 2. Мы не можем отличить 0 от -0, но в целом это хорошо.

Другим свойством этой системы является то, что первый бит является битом ‘sign’. если оно равно 1, оно отрицательное, если 0, это не так.

Давайте попробуем дополнить 2 1000 0000 0000 0000 0000 0000 0000 0000 . Сначала переверните биты: 0111 1111 1111 1111 1111 1111 1111 1111 . Затем добавьте 1: 1000 0000 0000 0000 0000 0000 0000 0000 . Подожди. Это… что у нас было!!

Да. и поскольку первый бит отрицательный, 1000 0000 0000 0000 0000 0000 0000 0000 ОТРИЦАТЕЛЬНЫЙ.

Возможно, вы забываете, что 0 — это вещь, а 0 не является ни положительным, ни отрицательным.

Итак, если 0 должно быть представимым и получает знаковый бит 0 (ноль в битах равен 0000000 … конечно), это означает, что «пробел» в половине всех представимых чисел, начинающихся с 0, теперь на единицу меньше, потому что 0 съел один слот. Это означает, что существует еще одно отрицательное число, которое можно представить против положительные числа. (или, альтернативно, что 0 «считается» положительным, поэтому 0 — это первое положительное число, а -1 — первое отрицательное число). Следовательно, должно быть по крайней мере 1 отрицательное число, которое не имеет положительного эквивалента в дополнении 2. Это число равно… 2 ^ 31. -2^31 подходит для 32-битной подписи. 2^31 не делает этого.

Давайте представим себе 3-разрядное число со знаком и дополнением 2. Мы можем перечислить их все:

 000 = 0
001 = 1
010 = 2
011 = 3
100 = -4
101 = -3
110 = -2
111 = -1
 

Обратите внимание, что там -4, а 4 нет, и обратите внимание, как мы рассмотрели 8 чисел. 2^3 = 8 — 3 бита могут представлять 8 чисел, не более того.

Ответ №2:

Из документации oracle мы получили это:

int: По умолчанию тип данных int представляет собой 32-разрядное целое число со знаком, дополняющее два, которое имеет минимальное значение -2 ^ 31 и максимальное значение 2 ^ 31-1. В Java SE 8 и более поздних версиях вы можете использовать тип данных int для представления 32-разрядного целого числа без знака, которое имеет минимальное значение 0 и максимальное значение 2 ^ 32-1. Используйте класс Integer для использования типа данных int в качестве целого числа без знака. См. Раздел Классы чисел для получения дополнительной информации. Статические методы, такие как compareUnsigned, divideUnsigned и т.д., были добавлены в класс Integer для поддержки арифметических операций с целыми числами без знака.

Из другого документа (простого и вполне понятного) мы получили:

Когда целое число подписывается, один из его битов становится знаковым битом, что означает, что максимальная величина числа уменьшается вдвое. (Таким образом, 32-разрядный int без знака может хранить до 2 ^ 32-1, тогда как его подписанный аналог имеет максимальное положительное значение 2 ^ 31-1.)

В Java все целочисленные типы подписаны (кроме char).

Это потому, что первый бит указывает знаковый бит. Максимальное положительное значение, которое он может сохранить 2^31 - 1 . Для этого доступно много ресурсов.