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

Я пытаюсь понять, как 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?

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


person Kevin Rave    schedule 16.11.2012    source источник


Ответы (10)


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

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

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

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

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

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

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

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

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

Источник

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

Хороший пример - из wiki, что связь с дополнением до двух реализуется с учетом того, что 256 = 255 + 1, а (255 - 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
person dreamcrash    schedule 16.11.2012

Целые числа 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.

person Sufian Latif    schedule 16.11.2012
comment
Точно мой вопрос: хранятся ли числа + ve в binary as is, а числа -ve - в two's complement? - person Kevin Rave; 16.11.2012
comment
Ну да. отрицательное число представляется компьютеру как два дополнения своего положительного значения. - person Sufian Latif; 16.11.2012
comment
@ 0605002: Не могли бы вы дать ссылку на этот ответ, если есть? Хотя я знал эти концепции, но никогда не думал о них таким образом. Самый простой, но точный ответ. - person Abhishek Singh; 19.01.2018
comment
Четыре года в университете, а я так и не понял дополнение на 2-е. Этот ответ научил меня большему. Это так печально, что таким простым вещам так загадочно учат во всем мире. - person Prashant Pandey; 14.08.2018
comment
Схема, которую вы здесь используете, - это уже 2 дополнения. Не так ли? - person KevinZhou; 08.07.2019

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

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

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

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

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

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

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

person matsev    schedule 16.11.2012

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

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»?

person Kanagavelu Sugumar    schedule 12.02.2015
comment
stackoverflow.com / questions / 11380062 / - person Kanagavelu Sugumar; 27.02.2015

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

person Sazzadur Rahaman    schedule 16.11.2012

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

person Joel    schedule 16.11.2012
comment
В дополнительном формате до двух положительное значение представляется в виде простого двоичного числа. написано в том же документе .. так что технически это правильно. :) - person Shashi; 03.09.2013

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

Например:

15 : 00000000 00000000 00000000 00001111
-15: 11111111 11111111 11111111 11110001

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

person Siva Padhy    schedule 07.02.2014

Спасибо, 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, поэтому представленное значение отрицательное.

person Maksim Dmitriev    schedule 09.01.2015

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

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

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

person Mangesh Gawali    schedule 27.12.2016