Как целые числа внутренне представлены на битовом уровне в Java?

84

Я пытаюсь понять, как Java хранит целые числа внутри. Я знаю, что все примитивные целые числа Java подписаны (кроме коротких?). Это означает, что в байте числа доступно на один бит меньше.

Мой вопрос: все ли целые числа (положительные и отрицательные) хранятся как два дополнения или только отрицательные числа в двух дополнениях?

Я вижу, что в спецификации написано 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?

Некоторые сказали, что все хранятся в дополнении до двух, а в одном ответе говорится, что только отрицательные числа хранятся как дополнение до двух.

Кевин Рэйв
источник

Ответы:

104

Начнем с обобщения примитивных типов данных Java:

byte : Тип данных Byte - это 8-битовое знаковое целое число с дополнением до двух .

Кратко : Краткий тип данных - это 16-разрядное целое число с дополнением до двух со знаком .

int: Тип данных Int представляет собой 32-битное знаковое целое число с дополнением до двух .

long: тип данных Long - это 64-битное целое число с дополнением до двух со знаком .

float: тип данных с плавающей запятой представляет собой 32-битное число с плавающей запятой одинарной точности IEEE 754 .

double : тип данных double - это 64-битный IEEE 754 с плавающей запятой двойной точности .

boolean: логический тип данных представляет один бит информации .

символ: тип данных char - это один 16-битный символ Unicode .

Источник

Два дополнения

"Хороший пример взят из взят вики что связь с дополнением до двух реализована, если отметить, что 256 = 255 + 1, а (255 - x) - это дополнение x до единиц x

0000 0111 = 7 двойное дополнение равно 1111 1001 = -7

как это работает, MSB (самый старший бит) получает отрицательное значение, поэтому в случае выше

-7 = 1001 = -8 + 0+ 0+ 1

Положительные целые числа обычно хранятся как простые двоичные числа (1 равно 1, 10 равно 2, 11 равно 3 и т. Д.).

Отрицательные целые числа хранятся как два дополнения их абсолютного значения. Дополнение до двух положительного числа - это при использовании этого обозначения отрицательное число.

Источник

Поскольку я получил несколько баллов за этот ответ, я решил добавить к нему дополнительную информацию.

Более подробный ответ:

Среди прочего, существует четыре основных подхода к представлению положительных и отрицательных чисел в двоичном формате, а именно:

  1. Знаковая величина
  2. Дополнение к одному
  3. Два дополнения
  4. Смещение

1. Знаковая величина

Использует старший бит для представления знака, остальные биты используются для представления абсолютного значения. Где 0 представляет положительное число, а 1 представляет отрицательное число , например:

1011 = -3
0011 = +3

Это представление проще. Однако вы не можете добавлять двоичные числа так же, как и десятичные числа, что затрудняет реализацию на аппаратном уровне. Более того, этот подход использует два двоичных шаблона для представления 0, -0 (1000) и +0 (0000) .

2. Дополнение к человеку

В этом представлении мы инвертируем все биты данного числа, чтобы найти его дополнительные. Например:

010 = 2, so -2 = 101 (inverting all bits).

Проблема с этим представлением заключается в том, что все еще существуют два шаблона битов для представления 0, отрицательного 0 (1000) и положительного 0 (0000).

3. Дополнение до двух

Чтобы найти отрицательное значение числа, в этом представлении мы инвертируем все биты, а затем добавляем один бит. Добавление одного бита решает проблему наличия двух битовых шаблонов, представляющих 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 Complement, помимо того, что имеет только одно представление для 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
крушение мечты
источник
61

Целые числа 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), а не отрицательный. В этом случае диапазон значений unsigned intсоставляет 0до 2^32 - 1, а intдиапазон значений - -2^31до2^31 - 1 .

С другой стороны, если вы рассматриваете два дополнения xкак~x + 1 (НЕ x плюс один), вот объяснение:

Для любого 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.

0605002
источник
Мой вопрос точно: хранятся ли числа + ve в, binary as isа числа -ve хранятся в two's complement?
Кевин Рэйв,
Ну да. отрицательное число представляется компьютеру как два дополнения его положительного значения.
0605002
4
Отличный ответ и объяснение Bonny @ 0605002, +1 :)
KM Rakibul Islam
@ 0605002: Не могли бы вы дать ссылку на этот ответ, если есть? Хотя я знал концепции, но никогда не думал о них таким образом. Самый простой, но точный ответ.
Абхишек Сингх
Четыре года в университете, и я никогда не понимал дополнение на 2-е. Этот ответ научил меня большему. Это так печально, что таким простым вещам так загадочно учат во всем мире.
Прашант Панди
10

Я запустил следующую программу, чтобы узнать это

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

Судя по выходным данным, он использовал два дополнения.

Dungeon Hunter
источник
1
Двойное дополнение до 10 есть 11111111 11111111 11111111 11110110. Ваш печатает, в то время как двоичный, как для 10, равен 1010. Значит, только числа -ve хранятся как два дополнения?
Кевин Рэйв,
проверьте статью вики en.wikipedia.org/wiki/… двойное дополнение, которое вы указали для 15, неверно
Dungeon Hunter
если бит msb начинается с 1, это будет отрицательное число
Dungeon Hunter
да, два дополнения из 10 составляют 11111111 11111111 11111111 11110110, что равно -10
Dungeon Hunter
+ ve чисел будут храниться в двоичном формате, оставив знаковый бит в дополнении до 2
Dungeon Hunter
5

Oracle предоставляет некоторую документацию по типам данных Java, которая может вас заинтересовать. В частности:

int: Тип данных int представляет собой 32-битное знаковое целое число с дополнением до двух. Он имеет минимальное значение -2 147 483 648 и максимальное значение 2 147 483 647 (включительно).

Кстати, short также хранится как дополнение до двух.

Мацев
источник
4

Положительные числа сохраняются / извлекаются как есть.

e.g) For +ve number 10; byte representation will be like 0-000 0010 
                                               (0 - MSB will represent that it is +ve).
So while retrieving based on MSB; it says it is +ve, 
so the value will be taken as it is. 

Но отрицательные числа будут сохранены после дополнения до 2 (кроме бита MSB), а бит MSB будет установлен в 1.

например) при сохранении -10 тогда

  0-000 0010  -> (1's complement) -> 0-111 1101 
              -> (2's complement) 0-111 1101 + 1 -> 0-111 1110
  Now MSB will be set to one, since it is negative no -> 1-111 1110

при извлечении он обнаружил, что MSB установлен в 1. Так что отрицательное значение нет. И дополнение до 2 будет выполняться кроме MSB.

  1-111 1110  --> 1-000 0001 + 1 --> 1-000 0010
  Since MSB representing this is negative 10 --> hence  -10 will be retrived.

Кастинг

Также обратите внимание, что когда вы приводите int / short к байту, только последний байт будет рассматриваться вместе с последним байтом MSB,

Возьмем, к примеру, короткий "-130", он может храниться, как показано ниже.

(MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110

Теперь приведение байтов заняло последний байт, который равен 0111 1110. (0-MSB) Так как MSB говорит, что это + ve значение, поэтому оно будет принято как есть. Это 126. (+ ve).

Возьмем другой пример "130", он может храниться, как показано ниже.

  0-000 000 1000 0010     (MSB = 0)

Теперь приведение байтов заняло последний байт, который равен 1000 0010. (1 = MSB) Поскольку MSB сообщает, что это значение -ve, будет выполнено дополнение до 2 и будет возвращено отрицательное число. Таким образом, в этом случае будет возвращено -126.

 1-000 0010  -> (1's complement) -> 1-111 1101 
             -> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110
               = -126

Разница между (int) (char) (byte) -1 AND (int) (short) (byte) -1

(byte)-1       -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111
(char)(byte)-1 -> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 

так же

(short)(byte)-1-> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 

Но

(int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111  = 65535
since char is unsigned; MSB won't be carry forwarded. 

И

(int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1
since short is signed; MSB is be carry forwarded. 

Рекомендации

Почему для представления отрицательных чисел используется дополнение до двух?

Что такое «Дополнение 2»?

Канагавелу Сугумар
источник
1
stackoverflow.com/questions/11380062/…
Канагавелу Сугумар
3

Самый старший бит (32-й) указывает, что число положительное или отрицательное. Если он равен 0, это означает, что число положительное и сохраняется в его фактическом двоичном представлении. но если оно равно 1, это означает, что число отрицательное и сохраняется в его дополнительном представлении до двух. Итак, когда мы даем вес -2 ^ 32 32-му биту при восстановлении целочисленного значения из его двоичного представления, мы получаем фактический ответ.

Саззадур Рахаман
источник
1
Добро пожаловать в StackOverflow! : D
0605002
3

Согласно этому документу , все целые числа подписаны и хранятся в формате дополнения до двух для java. Не уверен в его надежности ..

Джоэл
источник
«В формате дополнения до двух положительное значение представляется как прямое двоичное число». написано в том же документе .. так что технически это правильно. :)
Шаши
2

положительные числа хранятся непосредственно как двоичные. Комплимент 2 требуется для отрицательных чисел.

например:

15: 00000000 00000000 00000000 00001111
: 11111111 11111111 11111111 11110001

вот разница в битах со знаком.

Шива Падхи
источник
2

Спасибо, dreamcrash за ответ https://stackoverflow.com/a/13422442/1065835 ; на вики-странице они приводят пример, который помог мне понять, как узнать двоичное представление отрицательной копии положительного числа.

Например, используя 1 байт (= 2 полубайта = 8 бит), десятичное число 5 представлено как

0000 01012 Старший бит равен 0, поэтому шаблон представляет неотрицательное значение. Чтобы преобразовать в −5 в нотации с дополнением до двух, биты инвертируются; 0 становится 1, а 1 становится 0:

1111 1010 Здесь число является дополнением до единиц десятичного значения −5. Чтобы получить два дополнения, к результату добавляется 1, что дает:

1111 1011 Результатом является двоичное число со знаком, представляющее десятичное значение -5 в форме дополнения до двух. Самый старший бит равен 1, поэтому представленное значение отрицательное.

Максим Дмитриев
источник
1

Для положительного целого числа 2 значение дополнения совпадает с битом 0 MSB (like +14 2'complement is 01110).

Только для отрицательного целого числа мы вычисляем значение дополнения 2 ' (-14= 10001+1 = 10010).

Итак, окончательный ответ: оба значения (+ve and -ve)хранятся только в форме дополнения 2.

Мангеш Гавали
источник