Как целые числа внутренне представлены на битовом уровне в Java?
Я пытаюсь понять, как Java хранит целые числа внутри. Я знаю, что все примитивные целые числа Java имеют знак (кроме short?). Это означает, что в байте для числа доступно на один бит меньше.
Мой вопрос в том, все ли целые числа (положительные и отрицательные) хранятся как дополнение two или только отрицательные числа в дополнении two?
Я вижу, что в спецификациях указано x bit two's complement number
. Но я часто путаюсь.
Например:
int x = 15; // Stored as binary as is? 00000000 00000000 00000000 00001111?
int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010
Редактировать
Для ясности, x = 15
In binary as is: `00000000 00000000 00000000 00001111'
Two's complement: `11111111 11111111 11111111 11110001`
Итак, если ваш ответ all
числа хранятся как дополнение к двум, тогда:
int x = 15; // 11111111 11111111 11111111 11110001
int y = -22 // 11111111 11111111 11111111 11101010
Путаница здесь снова в том, что знак говорит, что оба являются отрицательными числами. Может быть, я неправильно читаю / недопонимаю это?
Редактировать Не уверен, что мой вопрос сбивает с толку. Вынужден изолировать вопрос:
Мой точный вопрос: хранятся ли положительные числа в binary as is
, в то время как отрицательные числа хранятся как two's complement
?
Некоторые сказали, что все хранятся в виде дополнения two, а в одном ответе говорится, что только отрицательные числа хранятся в виде дополнения two.
Переведено автоматически
Ответ 1
Давайте начнем с краткого описания примитивных типов данных Java:
байт: тип данных Byte представляет собой 8-разрядное целое число со знаком, дополняющее два.
Short: тип данных Short представляет собой 16-разрядное целое число со знаком, дополняющее два.
int: Тип данных Int представляет собой 32-разрядное целое число со знаком, дополняющее два.
long: Тип данных Long представляет собой 64-разрядное целое число со знаком, дополняющее двойку.
float: Тип данных Float представляет собой 32-разрядный стандарт IEEE 754 с плавающей запятой одинарной точности.
double: тип данных double - это 64-разрядный стандарт IEEE 754 с плавающей запятой двойной точности.
логическое значение: логический тип данных представляет один бит информации.
char: тип данных char представляет собой один 16-битный символ Unicode.
Дополнение Two
"Хороший пример взят из wiki, что связь с дополнением two реализуется путем указания, что 256 = 255 + 1, а (255 − x) - это дополнение единиц к x
0000 0111 = 7 дополнение two равно 1111 1001 = -7
это работает так, что MSB (самый значащий бит) получает отрицательное значение, поэтому в приведенном выше случае
-7 = 1001= -8 + 0+ 0+ 1
Положительные целые числа обычно хранятся в виде простых двоичных чисел (1 равно 1, 10 равно 2, 11 равно 3 и так далее).
Отрицательные целые числа хранятся как дополнение двойки к их абсолютному значению. Дополнение двойки к положительному числу при использовании этой записи является отрицательным числом.
Поскольку я получил несколько баллов за этот ответ, я решил добавить к нему больше информации.
Более подробный ответ:
Среди прочего, существует четыре основных подхода к представлению положительных и отрицательных чисел в двоичном формате, а именно:
- Величина со знаком
- Одно дополнение
- Дополнение Two
- Смещение
1. Величина со знаком
Использует старший бит для представления знака, остальные биты используются для представления абсолютного значения. Где 0 представляет собой положительное число, а 1 представляет собой отрицательное число, пример:
1011 = -3
0011 = +3
Это представление проще. Однако вы не можете добавлять двоичные числа так же, как вы добавляете десятичные числа, что затрудняет реализацию на аппаратном уровне. Более того, этот подход использует два двоичных шаблона для представления 0, -0 (1000) и +0 (0000).
2. Дополнение
В этом представлении мы инвертируем все биты данного числа, чтобы определить его комплементарность. Например:
010 = 2, so -2 = 101 (inverting all bits).
Проблема с этим представлением заключается в том, что все еще существуют два шаблона битов для представления 0, отрицательный 0 (1111) и положительный 0 (0000)
3. Дополнение Two
Чтобы найти отрицательное значение числа, в этом представлении мы инвертируем все биты, а затем добавляем один бит. Добавление одного бита решает проблему наличия двух битовых шаблонов, представляющих 0. В этом представлении у нас есть только один шаблон для 0 (0000).
Например, мы хотим найти двоичное отрицательное представление числа 4 (десятичное), используя 4 бита. Сначала преобразуем 4 в двоичное:
4 = 0100
затем мы инвертируем все биты
0100 -> 1011
наконец, мы добавляем один бит
1011 + 1 = 1100.
Итак, 1100 эквивалентно -4 в десятичной системе счисления, если мы используем двоичное представление с дополнением к двум с 4 битами.
Более быстрый способ найти дополнительный бит - зафиксировать первый бит как значение 1 и инвертировать остальные биты. В приведенном выше примере это было бы что-то вроде:
0100 -> 1100
^^
||-(fixing this value)
|--(inverting this one)
Представление дополнения Two, помимо того, что оно имеет только одно представление для 0, также добавляет два двоичных значения таким же образом, как и в десятичных четных числах с разными знаками. Тем не менее, необходимо проверить наличие случаев переполнения.
4. Смещение
Это представление используется для представления показателя степени в норме IEEE 754 для чисел с плавающей запятой. Его преимущество в том, что двоичное значение со всеми битами, равными нулю, представляет наименьшее значение. А двоичное значение со всеми битами равными 1 представляет наибольшее значение. Как следует из названия, значение кодируется (положительное или отрицательное) в двоичном формате с n битами со смещением (обычно 2^(n-1) или 2^(n-1)-1).
Итак, если мы используем 8 бит, значение 1 в десятичной системе счисления представляется в двоичной с использованием смещения 2 ^ (n-1) на значение:
+1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
converting to binary
1000 0001
Ответ 2
Целые числа Java состоят из 32 бит и всегда имеют знак. Это означает, что старший бит (MSB) работает как знаковый бит. Целое число, представленное через int
, представляет собой не что иное, как взвешенную сумму битов. Веса присваиваются следующим образом:
Bit# Weight
31 -2^31
30 2^30
29 2^29
... ...
2 2^2
1 2^1
0 2^0
Обратите внимание, что вес MSB отрицателен (фактически максимально возможное отрицательное значение), поэтому, когда этот бит включен, все число (взвешенная сумма) становится отрицательным.
Давайте смоделируем это с помощью 4-битных чисел:
Binary Weighted sum Integer value
0000 0 + 0 + 0 + 0 0
0001 0 + 0 + 0 + 2^0 1
0010 0 + 0 + 2^1 + 0 2
0011 0 + 0 + 2^1 + 2^0 3
0100 0 + 2^2 + 0 + 0 4
0101 0 + 2^2 + 0 + 2^0 5
0110 0 + 2^2 + 2^1 + 0 6
0111 0 + 2^2 + 2^1 + 2^0 7 -> the most positive value
1000 -2^3 + 0 + 0 + 0 -8 -> the most negative value
1001 -2^3 + 0 + 0 + 2^0 -7
1010 -2^3 + 0 + 2^1 + 0 -6
1011 -2^3 + 0 + 2^1 + 2^0 -5
1100 -2^3 + 2^2 + 0 + 0 -4
1101 -2^3 + 2^2 + 0 + 2^0 -3
1110 -2^3 + 2^2 + 2^1 + 0 -2
1111 -2^3 + 2^2 + 2^1 + 2^0 -1
Итак, дополнение двух не является исключительной схемой представления отрицательных целых чисел, скорее мы можем сказать, что двоичное представление целых чисел всегда одно и то же, мы просто отрицаем вес самого значащего бита. И этот бит определяет знак целого числа.
В C есть ключевое слово unsigned
(недоступно в java), которое можно использовать для объявления unsigned int x;
. В целых числах без знака вес MSB положительный (2^31
), а не отрицательный. В этом случае диапазон an unsigned int
равен 0
to 2^32 - 1
, в то время как an int
имеет диапазон -2^31
to 2^31 - 1
.
С другой точки зрения, если вы рассматриваете дополнение двух x
как ~x + 1
(НЕ x плюс один), вот объяснение:
Для any x
, ~x
является просто побитовой инверсией x
, поэтому везде, где x
есть 1
-бит, ~x
там будет 0
-бит (и наоборот). Итак, если вы сложите их, переноса при сложении не будет, и сумма будет просто целым числом, каждый бит которого 1
.
Для 32-битных целых чисел:
x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111
x + ~x + 1 = 1111 1111 1111 1111 1111 1111 1111 1111 + 1
= 1 0000 0000 0000 0000 0000 0000 0000 0000
Самый левый 1
-бит будет просто отброшен, потому что он не помещается в 32-битный формат (целочисленное переполнение). Итак,
x + ~x + 1 = 0
-x = ~x + 1
Итак, вы можете видеть, что отрицательное значение x
может быть представлено через ~x + 1
, которое мы называем дополнением двух x
.
Ответ 3
Я запустил следующую программу, чтобы узнать это
public class Negative {
public static void main(String[] args) {
int i =10;
int j = -10;
System.out.println(Integer.toBinaryString(i));
System.out.println(Integer.toBinaryString(j));
}
}
Вывод
1010
11111111111111111111111111110110
Из выходных данных кажется, что в нем использовалось дополнение two .
Ответ 4
Oracle предоставляет некоторую документацию, касающуюся типов данных Java, которая может показаться вам интересной. В частности:
int: тип данных int представляет собой 32-разрядное целое число, дополняющее двойку со знаком. Минимальное значение -2 147 483 648, а максимальное - 2 147 483 647 (включительно).
Кстати, short также хранится как дополнение к two .