Доповняльний код

Доповняльний код (англ. two’s complement, «доповнення до 2») — найпоширеніший спосіб подання від'ємних чисел у комп'ютерах. Дозволяє замість команди віднімання використовувати команду додавання, для знакових і беззнакових чисел, що зменшує вимоги до архітектури комп'ютера. Доповняльний код від'ємного числа можна отримати так: інвертувати модуль числа у двійковому вигляді («перше доповнення») і додати одиницю («друге доповнення») або відняти число від нуля. Математично доповняльний код Xдоп = 2N+1 — X, де X — число, яке треба представити у доповняльному коді, N — к-сть розрядів числа.

Найстарший біт
0 1 1 1 1 1 1 1 = 127
0 1 1 1 1 1 1 0 = 126
0 0 0 0 0 0 1 0 = 2
0 0 0 0 0 0 0 1 = 1
0 0 0 0 0 0 0 0 = 0
1 1 1 1 1 1 1 1 = −1
1 1 1 1 1 1 1 0 = −2
1 0 0 0 0 0 0 1 = −127
1 0 0 0 0 0 0 0 = −128

Восьмирозрядні доповняльні коди

Подання від'ємного числа у доповняльному коді

При записі числа в доповняльному коді старший розряд є знаковим. Якщо його значення дорівнює 0, то в решті розрядів записане додатне двійкове число, що збігається з прямим кодом.

Двійкове 8-розрядне число зі знаком в доповняльному коді може представляти будь-яке ціле в діапазоні від -128 до +127. Якщо старший розряд дорівнює нулю, то найбільше ціле число, що може бути записане в останніх 7 розрядах, дорівнює , що дорівнює 127.

Приклади:

Десяткове
відображення
Двійкове відображення (8 біт)
прямий обернений доповняльний
127        01111111        01111111        01111111       
1        00000001        00000001        00000001       
0        00000000        00000000        00000000       
-0        10000000        11111111        ---       
-1        10000001        11111110        11111111       
-2        10000010        11111101        11111110       
-3        10000011        11111100        11111101       
-4        10000100        11111011        11111100       
-5        10000101        11111010        11111011       
-6        10000110        11111001        11111010       
-7        10000111        11111000        11111001       
-8        10001000        11110111        11111000       
-9        10001001        11110110        11110111       
-10        10001010        11110101        11110110       
-11        10001011        11110100        11110101       
-127        11111111        10000000        10000001       
-128        ---        ---        10000000       

Доповняльний код для десяткових чисел

Це саме можна використовувати і в комп'ютерному поданні десяткові числа: для кожного розряду цифра X замінюється на 9-X, і до одержаного числа додається 1. Наприклад, при використанні чотиризначних чисел -0081 замінюється на 9919 (9919 + 0081 = 0000, п'ятий розряд викидається).

При застосуванні тієї ж ідеї до звичної 10-кової системи числення вийде (наприклад, для гіпотетичного процесора, що використовує 10-ткову систему числення):

10-кова система числення
("простий" запис)
10-кова система числення,
доповняльний код
... ...
13 0013
12 0012
11 0011
10 0010
9 0009
8 0008
... ...
2 0002
1 0001
0 0000
-1 9999
-2 9998
-3 9997
-4 9996
... ...
-9 9991
-10 9990
-11 9989
-12 9988
... ...

Перетворення у доповняльний код

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

  1. Якщо число, записане в прямому коді, додатне, то до нього дописується старший (знаковий) розряд, рівний 0, і на цьому перетворення закінчується;
  2. Якщо число, записане в прямому коді, від'ємне, то всі розряди числа (крім знакового) інвертуються, а до результату додається 1. До отриманого числа дописується старший (знаковий) розряд, рівний 1.

Приклад. Перетворимо від'ємне число -5, записане в прямому коді, в доповняльний.

Прямий код числа -5, взятого за модулем:

101 

Інвертуємо всі розряди числа, отримуючи таким чином обернений код:

010

Додамо до результату 1

011

Допишемо зліва знаковий одиничний розряд

1011

Для зворотного перетворення використовується той же алгоритм. А саме:

1011

Інвертуємо всі розряди числа, отримуючи таким чином обернений код:

0100

Додамо до результату 1

0101

І перевіримо, додавши до доповняльного коду

 0101 + 1011 = 10000, п'ятий розряд викидається.

Р-адичні числа

В системі p-адичних чисел зміна знаку числа здійснюється перетворенням числа в його доповняльний код. Наприклад, якщо використовується 5-кова система числення, то число, протилежне 1000 … (1), так само є 4444 …. (-1).

Арифметичні операції

Додавання

Додавання двох чисел у доповняльному коді не потребує додаткових дій якщо доданки мають протилежні знаки, у такому випадку знак суми визначається автоматично. Приклад додавання 15 та -5:

  11111 111   (перенесення)
   0000 1111  (15)
 + 1111 1011  (−5)
 ===================
   0000 1010  (10)

Цей процес залежить від обмеження вісьмома бітами: перенесення до відсутнього дев'ятого найстаршого біту ігнорується, що повертає нам правильний результат 1010.

Найстарші два біти рядка перенесених цифр містять важливу інформацію: коли обчислення призвело до арифметичного переповнення, число занадто велике для подання у двійковій системі (у цьому випадку більше ніж 8 біт). Переповнення існує тоді, коли ці два біти відрізняються один від одного. Як уже згадувалося, знак кодується в старшому біті результату.

Іншими словами, коли обидва старші біти рядка перенесення 1 або 0, обчислення дало правильний результат, але коли вони утворюють комбінацію «10» або «01», трапилося знакове переповнення. Зручно те, що операція XOR, виконана над цими двома бітами, показує чи була операція виконана коректно. Як приклад, розглянемо 4-бітове додавання 7 та 3:

  0111   (перенесення)
   0111  (7)
 + 0011  (3)
 =============
   1010  (−6)  некоректно!

Таким чином, два найстарших біти рядка перенесення утворюють комбінацію «01», що позначає арифметичне переповнення. Справді, 10102 = 1010, що знаходиться за межами 4-бітових чисел −8 та 7.

Загалом, будь-які N-бітові числа можуть бути додані без переповнення, якщо перед цим їх перевести до N + 1 бітового вигляду і після цього додати. Межі N + 1 бітових чисел більш ніж вдвічі перевищують межі N-бітових чисел, тож у новій системі переповнення ніколи не виникне.

Реалізація алгоритму перетворення в доповнювальний код (для 8-бітних чисел)

Pascal

if a<0
  then a:=((not a) or 128) + 1;

C/C++

int8_t convert(int8_t a) {
    return ~a + 1;
}

Переваги та недоліки

Переваги

  • Комірка пам'яті може містити як n-бітні додатні числа, так і (n−1)-бітні числа зі знаком, причому операції додавання, віднімання і зсуву вліво однакові для обох форматів.
  • Відсутність числа «-0». У оберненому коді таке число є.

Недоліки

  • Стосовно складних форматів (таких, як рухома кома або двійково-десятковий код) переваги втрачаються.
  • Модуль найбільшого числа не дорівнює модулю найменшого. Наприклад, для знакової цілої 8-бітової змінної найбільше число це 12710 = 7F16 = 011111112, а найменше: −12810 = 8016,доп. код = 100000002,доп. код. Відповідно, не для кожного числа можна записати протилежне. Операція зміни знаку може вимагати додаткової перевірки.

Приклад програмного перетворення

Якщо відбувається читання даних з файла або ділянки пам'яті, де вони зберігаються в двійковому доповняльному коді (наприклад, файл WAVE), може виявитися необхідним обернути байти. Якщо дані зберігаються в 8 бітах, необхідно, щоб значення 128—255 були від'ємними.

C# .NET / C style

byte b1 = 254; //11111110 (двійкове)
byte b2 = 121; //01111001 (двійкове)
byte c = 1<<(sizeof(byte)*8-1);  //2 підноситься до 7 степеня. Результат: 10000000 (двійкове)
byte b1Conversion=(c ^ b1) - c;  //Результат: -2. А це, фактично, двійковий доповнювальний код.
byte b2Conversion=(c ^ b2) - c;  //Результат залишається 121, тому що знаковий розряд - нуль.

Див. також


Strategi Solo vs Squad di Free Fire: Cara Menang Mudah!