Як цілі числа внутрішньо представлені на бітовому рівні в Java?


83

Я намагаюся зрозуміти, як 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?

Деякі сказали, що всі зберігаються у доповненні двох, а одна відповідь говорить, що як від’ємні доповнення - лише негативні числа.


Доповнення двох обов’язково означає, що позитивні числа представлені фактичними бітовими значеннями цього числа ... принаймні, наскільки я це розумію. РЕДАГУВАТИ: Крім того, комплімент двох означає один біт менше в загальній кількості байтів у примітиві, а не один біт менше за байт.
LJ2,

ваше припущення правильне: додатні та від’ємні числа є доповненням двох, а ваше xі yправильне.
jlordo

Побічна примітка: це щось на кшталт WTF, що Java, мова епохи Інтернету, не має типу даних для представлення, наприклад. Номер порту TCP / IP (16-бітове значення без підпису) точно, що часом призводить до потворного коду.
Гайд,

перевірте статтю wiki en.wikipedia.org/wiki/ ... номер доповнення 2, який ви вказали для 15, помилковий
Dungeon Hunter

@hyde 'Дійсно потворний код', наприклад?
Маркіз Лорнський

Відповіді:


102

Почнемо з узагальнення примітивних типів даних Java:

байт : Тип даних байт - це ціле число доповнення 8-бітового двозначного знака .

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

int: тип даних Int - це 32-розрядне ціле число доповнень із підписом .

long: тип даних long - це ціле доповнення 64-розрядного підписаного двоє .

float: тип даних з плаваючою є 32-бітовою плаваючою точкою IEEE 754 з однією точністю .

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

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

char: тип даних char - це єдиний 16-розрядний символ Unicode .

Джерело

Доповнення двох

"Хорошим прикладом є вікі, що відношення до доповнення двох реалізується, зазначаючи, що 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)

Представлення Complement 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
Моє питання точно: Чи зберігаються + ve номери, binary as isтоді як -ve номери зберігаються two's complement?
Kevin Rave

1
Позитивні цілі числа, як правило, зберігаються як прості двійкові числа, а від’ємні цілі числа - як доповнення двох.
dreamcrash

Це відповідає на моє запитання. Будь-яке джерело? Я не знайшов жодного документа, який би чітко про це говорив.
Kevin Rave

вищевказане посилання з ecomware.com не працює @dreamcrash, чи можете ви надати інше?
Рам Патра

@Ramswaroop Привіт, як про це один stackoverflow.com/questions/1049722/what-is-2s-complement
dreamcrash

61

Цілі числа Java мають 32 біти і завжди підписані. Це означає, що найзначніший біт (MSB) працює як знаковий біт. Ціле число, представлене символом an, 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є 1-bit, там ~xбуде 0-bit (і навпаки). Отже, якщо їх скласти, додавання не матиме перенесення, а сума буде просто цілим числом, кожен біт якого є 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.


Моє питання точно: Чи зберігаються + ve номери, binary as isтоді як -ve номери зберігаються two's complement?
Kevin Rave

Ну так. від’ємне число представляється комп’ютеру як доповнення його двох позитивних значень.
0605002

4
Чудова відповідь та пояснення Бонні @ 0605002, +1 :)
К.М. Ракібул Іслам

@ 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

З вихідних даних здається, що він використовував доповнення двох.


1
Двійки доповнення 10 є 11111111 11111111 11111111 11110110. Ваші відбитки, а двійковий файл, як для 10, це 1010. Тож лише -ve числа зберігаються як доповнення до двох?
Kevin Rave

перевірте статтю wiki en.wikipedia.org/wiki/... номер доповнення 2, який ви вказали для 15, помилковий
Dungeon Hunter

якщо біт msb починається з 1, це буде від'ємним числом
Dungeon Hunter

так, доповнення двійки 10 - це 11111111 11111111 11111111 11110110, тобто -10
Dungeon Hunter

+ номери зберігатимуться як двійкові, залишаючи знаковий біт у доповненні 2
Dungeon Hunter

4

Oracle надає деяку документацію щодо типів даних Java, яка може вам здатися цікавою. Зокрема:

int: Тип даних int - це 32-розрядне ціле число доповнень із підписом. Він має мінімальне значення -2,147,483,648 та максимальне значення 2,147,483,647 (включно).

До речі, короткий також зберігається як доповнення для двох.


3

Згідно з цим документом , всі цілі числа підписуються та зберігаються у форматі двох доповнень для Java. Не впевнений у своїй надійності ..


"У форматі доповнення двох позитивне значення представляється у вигляді прямого двійкового числа." написано в тому самому документі .. тому технічно це правильно. :)
Шаші

3

Позитивні числа зберігаються / отримуються як є.

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



2

Найбільш значущий біт (32-й) вказує на те, що число є позитивним чи негативним. Якщо воно дорівнює 0, це означає, що число є додатним, і воно зберігається у своєму фактичному двійковому поданні. але якщо воно дорівнює 1, це означає, що число від’ємне і зберігається у поданні доповнення двох. Отже, коли ми надаємо вагу -2 ^ 32 32-му біту, відновлюючи ціле значення з його двійкового подання, ми отримуємо фактичну відповідь.


1
Ласкаво просимо до StackOverflow! : D
0605002

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.

наприклад:

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

ось різниця у підписаному біті.


1

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

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

Отже, остаточна відповідь полягає в тому, що обидва значення (+ve and -ve)зберігаються лише у формі 2'доповнення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.