Дополнительный кодДополнительный код (англ. "two’s complement", иногда "twos-complement") — наиболее распространённый способ представления отрицательных целых чисел в компьютерах. Он позволяет заменить операцию вычитания на операцию сложения и сделать операции сложения и вычитания одинаковыми для знаковых и беззнаковых чисел, что упрощает архитектуру ЭВМ. В англоязычной литературе «обратный код» (инверсия прямого кода) называют «первым дополнением» (англ. "ones' complement"), а «дополнительный код» называют «вторым дополнением» (англ. "two’s complement"). Дополнительный код для отрицательного числа можно получить инвертированием его двоичного модуля (получается "первое дополнение") и прибавлением к инверсии единицы (получается "второе дополнение"), либо вычитанием числа из нуля (сразу получается "второе дополнение"). ИсторияТо, что отрицательные числа в дополнительном коде можно складывать на сумматоре, было известно ещё во времена Паскаля, который и применил это свойство в своей суммирующей машине "Паскалина". Представление отрицательного числа в дополнительном кодеПри записи числа в дополнительном коде старший разряд является знаковым. Если значение старшего разряда равно 0, то это значит, что в остальных разрядах записано положительное двоичное число, совпадающее с прямым кодом. Двоичное 8-разрядное число со знаком в дополнительном коде может представлять любое целое в диапазоне от −128 до +127. Если старший разряд равен нулю, то наибольшее целое число, которое может быть записано в оставшихся 7 разрядах, равно . Примеры:
Дополнительный код в иной системе счисленияТот же принцип можно использовать и в компьютерном представлении любой системы счисления, например, для десятичных чисел. Преобразования на примере десятичной системы счисления[1]Положительное числоИзменение значений текущих разрядов числа не производится, но дописывается знаковый старший разряд, значение которого равно 0. Например число [+12'345] будет иметь следующее представление - [012'345] Отрицательное числоДописываем знаковый старший разряд, равный большей цифре данной системы счисления, в нашем случае - это 9, а также изменяем остальные разряды по определённому правилу; пусть значение цифры каждого разряда будет представлено переменной , кроме знакового, тогда представим следующий алгоритм действий:
Идея представления десятичного (как и любого другого) числа в дополнительном коде, идентична правилам для двоичной системы счисления и может использоваться в гипотетическом процессоре:
Арифметика в дополнительном кодеСложение и вычитаниеОба числа представляются в дополнительном коде. Дополнительный код обоих чисел имеет одинаковое количество разрядов. В данном представлении числа складываются. Знаки разные: Если в процессе сложения образуется выходящий за пределы первоначальных чисел разряд, то он опускается. Результирующее значение считается положительным, где прямой и дополнительный коды являются идентичными. Иначе — отрицательным в виде дополнительного кода. Например:
Знаки одинаковые:
Например:
Преобразование в дополнительный кодИз прямого в дополнительный кодПреобразование числа из прямого кода в дополнительный осуществляется по следующему алгоритму.
Для примера преобразуем отрицательное число , записанное в прямом коде, в дополнительный код. Прямой код отрицательного числа :
Изменение знака числаДля преобразования отрицательного числа , записанного в дополнительном коде, в положительное число , записанное в прямом коде, используется похожий алгоритм:
И проверим, сложив получившееся записи и : p-адические числаВ системе p-адических чисел изменение знака числа осуществляется преобразованием числа в его дополнительный код. Например, если используется 5-ричная система счисления, то число, противоположное 00015 (110), равно 44445 (−110). Реализация алгоритма нахождения модуля для дополнительного кодаDEF FN TwosComplAbs%(a%)
IF a% < 0 THEN a% = NOT(a% - 1)
FN TwosComplAbs% = a%
END DEF
Pascalfunction TwosComplAbs(a: integer): integer;
begin
if (a < 0) then TwosComplAbs := (not a) + 1
else TwosComplAbs := a;
end;
C/C++int twos_compl_abs(int a)
{
if (a < 0) a = (~a) + 1;
return a;
}
Реализация без ветвленияС помощью следующей формулы можно вычислить модуль числа без ветвления[2]:
где: — Операция исключающего "или"; Следующий код на языке Си вычисляет модуль по этой формуле: int32_t fastabs32(int32_t num)
{
int32_t mask = (num >> 31);
return ((num ^ mask) - mask);
}
Преимущества и недостаткиПреимущества
Недостатки
Пример программного преобразованияЕсли происходит чтение данных из файла или области памяти, где они хранятся в двоичном дополнительном коде (например, WAV файл), может оказаться необходимым преобразовать байты. Если данные хранятся в 8 битах, необходимо, чтобы значения 128-255 были отрицательными. C# .NET / C stylebyte 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, потому что знаковый разряд - ноль.
Расширение знакаРасширение знака (англ. sign extension[en]) — операция над двоичным числом, которая позволяет увеличить разрядность числа с сохранением знака и значения. Выполняется добавлением цифр со стороны старшего значащего разряда. Если число положительное (старший разряд равен 0), то добавляются нули, если отрицательное (старший разряд равен 1) — единицы. ПримерПримечание: Добавленные цифры подчёркнуты
См. также
Литература
Примечания
|
Portal di Ensiklopedia Dunia