Как целые числа внутренне представлены на битовом уровне в 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


Edit



чтобы было понятно, 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


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



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



мой вопрос точно: положительные числа хранятся в binary as is в то время как отрицательные числа хранятся в виде two's complement?



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

845   10  

10 ответов:

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

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

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

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

долгих: тип данных Long-это 64-разрядное два дополняют целое число.

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

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

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

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, 100...0 и 0....0.

2. Одно дополнение

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

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

проблема этого представления заключается в том, что все еще существуют два битовых шаблона для представления 0 (00..0 и 11..1)

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

чтобы найти отрицательное число, в этом представлении мы инвертируем все биты, а затем добавляем один немного. Добавление одного бита решает проблему наличия двух битовых шаблонов, представляющих 0. В этом представлении у нас есть только один (00...0).

например, мы хотим найти двоичное отрицательное представление 4 (десятичное), используя 4 бита. Сначала мы преобразуем 4 в двоичный код:

4 = 0100

затем мы инвертируем все биты

0100 -> 1011

наконец, мы добавим один бит

1011 + 1 = 1100.

таким образом, 1100 эквивалентно -4 в десятичной системе счисления, если мы используем двоичный код дополнения представление с 4 бита.

более быстрый способ найти комплементарный-это зафиксировать первый бит в качестве значения 1 и инвертировать оставшиеся биты. В приведенном выше примере это будет что-то вроде:

0100 -> 1100
^^ 
||-(fixing this value)
|--(inverting this one)

два дополняют представление, помимо того, что имеют только одно представление для 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

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

С другой точки зрения, если вы считаете дополнения two 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, который мы называем дополнения two x.

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

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.

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

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

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

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

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

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

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

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

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

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

положительные числа хранятся/получены как это.

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) (байт) -1 и(int)(короткий) (байт) -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. 

ссылки

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

что такое "дополнение 2"?

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

например:

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

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

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

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

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

Comments

    Ничего не найдено.