Представление положительных и отрицательных чисел в памяти компьютера. Прямой и дополнительный код числа
Прямой код – это представление числа в двоичной системе счисления, при котором первый (старший) разряд отводится под знак числа. Если число положительное, то в левый разряд записывается 0; если число отрицательное, то в левый разряд записывается 1.
Таким образом, в двоичной системе счисления, используя прямой код, в восьмиразрядной ячейке (байте) можно записать семиразрядное число. Например:
0 0001101 – положительное число
1 0001101 – отрицательное число
Количество значений, которые можно поместить в семиразрядной ячейке со знаком в дополнительном разряде равно 256. Это совпадает с количеством значений, которые можно поместить в восьмиразрядную ячейку без указания знака. Однако диапазон значений уже другой, ему принадлежат значения от -128 до 127 включительно (при переводе в десятичную систему счисления).
При этом в вычислительной технике прямой код используется почти исключительно для представления положительных чисел.
Для отрицательных чисел используется так называемый дополнительный код. Это связано с удобством выполнения операций над числами электронными устройствами компьютера.
Дополнительный код
В дополнительном коде, также как и прямом, первый разряд отводится для представления знака числа. Прямой код используется для представления положительных чисел, а дополнительный – для представления отрицательных. Поэтому, если в первом разряде находится 1, то мы имеем дело с дополнительным кодом и с отрицательным числом.
Все остальные разряды числа в дополнительном коде сначала инвертируются, т.е. заменяются противоположными (0 на 1, а 1 на 0). Например, если 1 0001100 – это прямой код числа, то при формировании его дополнительного кода, сначала надо заменить нули на единицы, а единицы на нули, кроме первого разряда. Получаем 1 1110011. Но это еще не окончательный вид дополнительного кода числа.
Далее следует прибавить единицу к получившемуся инверсией числу:
1 1110011 + 1 = 1 1110100
В итоге и получается число, которое принято называть дополнительным кодом числа.
Причина, по которой используется дополнительный код числа для представления отрицательных чисел, связана с тем, что так проще выполнять математические операции. Например, у нас два числа, представленных в прямом коде. Одно число положительное, другое – отрицательное и эти числа нужно сложить. Однако просто сложить их нельзя. Сначала компьютер должен определить, что это за числа. Выяснив, что одно число отрицательное, ему следует заменить операцию сложения операцией вычитания. Потом, машина должна определить, какое число больше по модулю, чтобы выяснить знак результата и определиться с тем, что из чего вычитать. В итоге, получается сложный алгоритм. Куда проще складывать числа, если отрицательные преобразованы в дополнительный код. Это можно увидеть на примерах ниже.
Операция сложения положительного числа и отрицательного числа, представленного в прямом коде
- Прямой код числа 5: 0 000 0101
Прямой код числа -7: 1 000 0111 - Два исходных числа сравниваются. В разряд знака результата записывается знак большего исходного числа.
- Если числа имеют разные знаки, то вместо операции сложения используется операция вычитания из большего по модулю значения меньшего. При этом первый (знаковый) разряд в операции не участвует.
_ 000 0111 000 0101 ------------- 000 0010
Операция сложения положительного числа и отрицательного числа, представленного в дополнительном коде
- Прямой код числа 5: 0 000 0101
Прямой код числа -7: 1 000 0111 - Формирование дополнительного кода числа -7.
Прямой код : 1 000 0111
Инверсия : 1 111 1000
Добавление единицы: 1 111 1001 - Операция сложения.
0 000 0101 + 1 111 1001 -------------- 1 111 1110
Прямой, обратный и дополнительный коды
Очень часто в вычислениях должны использоваться не только положительные, но и отрицательные числа.
Число со знаком в вычислительной технике представляется путем представления старшего разряда числа в качестве знакового .
Принято считать, что 0 в знаковом разряде означает знак «плюс» для данного числа, а 1 – знак «минус».
Выполнение арифметических операций над числами с разными знаками представляется для аппаратной части довольно сложной процедурой. В этом случае нужно определить большее по модулю число, произвести вычитание и присвоить разности знак большего по модулю числа.
Применение дополнительного кода позволяет выполнить операцию алгебраического суммирования и вычитания на обычном сумматоре. При этом не требуется определения модуля и знака числа.
Прямой код представляет собой одинаковое представление значимой части числа для положительных и отрицательных чисел и отличается только знаковым битом. В прямом коде число 0 имеет два представления «+0» и «–0».
Обратный код для положительных чисел имеет тот же вид, что и прямой код, а для отрицательных чисел образуется из прямого кода положительного числа путем инвертирования всех значащих разрядов прямого кода. В обратном коде число 0 также имеет два представления «+0» и «–0».
Дополнительный код для положительных чисел имеет тот же вид, что и прямой код, а для отрицательных чисел образуется путем прибавления 1 к обратному коду. Добавление 1 к обратному коду числа 0 дает единое представление числа 0 в дополнительном коде. Однако это приводит к асимметрии диапазонов представления чисел относительно нуля.
Так, в восьмиразрядном представлении диапазон изменения чисел с учетом знака.
Таблица прямого, обратного и дополнительного кода 4-битных чисел. Для наглядности представления всего диапазона чисел примем, что сетка представления чисел 4-разрядная, где старший разряд (3) — знаковый, а 0-2 разряды содержат значение числа.
Число | Прямой код | Обратный код | Дополнительный код |
-8 | — | — | 1000 |
-7 | 1111 | 1000 | 1001 |
-6 | 1110 | 1001 | 1010 |
-5 | 1101 | 1010 | 1011 |
-4 | 1100 | 1011 | 1100 |
-3 | 1011 | 1100 | 1101 |
-2 | 1010 | 1101 | 1110 |
-1 | 1001 | 1110 | 1111 |
0 0 |
1000 0000 |
1111 0000 |
0000 |
1 | 0001 | 0001 | 0001 |
2 | 0010 | 0010 | 0010 |
3 | 0011 | 0011 | 0011 |
4 | 0100 | 0100 | 0100 |
5 | 0101 | 0101 | 0101 |
6 | 0110 | 0110 | 0110 |
7 | 0111 | 0111 | 0111 |
Представление целых чисел: прямой код, код со сдвигом, дополнительный код
Выбор способа хранения целых чисел в памяти компьютера — не такая тривиальная задача, как могло бы показаться на первый взгляд. Желательно, чтобы этот способ:
- не требовал усложнения архитектуры процессора для выполнения арифметических операций с отрицательными числами,
- не усложнял арифметические действия,
- хранил бы одинаковое количество положительных и отрицательных чисел.
Рассмотрим разные методы представления.
Прямой код
Нумерация двоичных чисел в прямом представлении
При записи числа в прямом коде (англ. Signed magnitude representation) старший разряд является знаковым разрядом. Если его значение равно нулю, то представлено положительное число или положительный ноль, если единице, то представлено отрицательное число или отрицательный ноль. В остальных разрядах (которые называются цифровыми) записывается двоичное представление модуля числа. Например, число [math] -5 [/math] в восьмибитном типе данных, использующем прямой код, будет выглядеть так: [math] 10000101 [/math] .
Таким способом в [math] n [/math] -битовом типе данных можно представить диапазон чисел [math] [-2^ + 1; 2^ — 1] [/math] .
Достоинства представления чисел с помощью прямого кода
- Получить прямой код числа достаточно просто.
- Из-за того, что [math]0[/math] обозначает [math]+[/math] , коды положительных чисел относительно беззнакового кодирования остаются неизменными.
- Количество положительных чисел равно количеству отрицательных.
Недостатки представления чисел с помощью прямого кода
- Выполнение арифметических операций с отрицательными числами требует усложнения архитектуры центрального процессора (например, для вычитания невозможно использовать сумматор, необходима отдельная схема для этого).
- Существуют два нуля: [math] -0 [/math] [math](100 \ldots 000) [/math] и [math] +0 [/math] [math] (000 \ldots 000) [/math] , из-за чего усложняется арифметическое сравнение.
Из-за весьма существенных недостатков прямой код используется очень редко.
Код со сдвигом
Код со сдвигом. Как видно, двоичное представление зациклено по модулю [math]1000..000_[/math] ( [math]n[/math] нулей)(2)>
При использовании кода со сдвигом (англ. Offset binary) целочисленный отрезок от нуля до [math] 2^n [/math] ( [math] n [/math] — количество бит) сдвигается влево на [math] 2^ [/math] , а затем получившиеся на этом отрезке числа последовательно кодируются в порядке возрастания кодами от [math] 000 \dots 0 [/math] до [math] 111 \dots 1 [/math] . Например, число [math] -5 [/math] в восьмибитном типе данных, использующем код со сдвигом, превратится в [math] -5 + 128 = 123 [/math] , то есть будет выглядеть так: [math] 01111011 [/math] .
По сути, при таком кодировании:
- к кодируемому числу прибавляют [math] 2^ [/math] ;
- переводят получившееся число в двоичную систему исчисления.
Можно получить диапазон значений [math] [-2^; 2^ — 1][/math] .
Достоинства представления чисел с помощью кода со сдвигом
- Не требуется усложнение архитектуры процессора.
- Нет проблемы двух нулей.
Недостатки представления чисел с помощью кода со сдвигом
- При арифметических операциях нужно учитывать смещение, то есть проделывать на одно действие больше (например, после «обычного» сложения двух чисел у результата будет двойное смещение, одно из которых необходимо вычесть).
- Ряд положительных и отрицательных чисел несимметричен.
Из-за необходимости усложнять арифметические операции код со сдвигом для представления целых чисел используется не часто, но зато применяется для хранения порядка вещественного числа.
Дополнительный код (дополнение до единицы)
Нумерация двоичных чисел в представлении c дополнением до единицы. В отличии от кода со сдвигом, нулю соответствуют коды [math] 00. 000 [/math] и [math] 11. 111 [/math]
В качестве альтернативы представления целых чисел может использоваться код с дополнением до единицы (англ. Ones’ complement).
Алгоритм получения кода числа:
- если число положительное, то в старший разряд (который является знаковым) записывается ноль, а далее записывается само число;
- если число отрицательное, то код получается инвертированием представления модуля числа (получается обратный код);
- если число является нулем, то его можно представить двумя способами: [math] +0 [/math] [math](000 \ldots 000) [/math] или [math] -0 [/math] [math] (111 \ldots 111) [/math] .
Пример: переведём число [math] -13 [/math] в двоичный восьмибитный код. Прямой код модуля [math] -13 [/math] : [math] 00001101 [/math] , инвертируем и получаем [math] 11110010 [/math] . Для получения из дополнительного кода самого числа достаточно инвертировать все разряды кода.
Таким способом можно получить диапазон значений [math] [-2^+1; 2^ — 1] [/math] .
Достоинства представления чисел с помощью кода с дополнением до единицы
- Простое получение кода отрицательных чисел.
- Из-за того, что [math]0[/math] обозначает [math]+[/math] , коды положительных чисел относительно беззнакового кодирования остаются неизменными.
- Количество положительных чисел равно количеству отрицательных.
Недостатки представления чисел с помощью кода с дополнением до единицы
- Выполнение арифметических операций с отрицательными числами требует усложнения архитектуры центрального процессора.
- Существуют два нуля: [math] +0 [/math] и [math] -0 [/math] .
Дополнительный код (дополнение до двух)
Нумерация двоичных чисел в представлении c дополнением до двух.
Чаще всего для представления отрицательных чисел используется код с дополнением до двух (англ. Two’s complement).
Алгоритм получения дополнительного кода числа:
- если число неотрицательное, то в старший разряд записывается ноль, далее записывается само число;
- если число отрицательное, то все биты модуля числа инвертируются, то есть все единицы меняются на нули, а нули — на единицы, к инвертированному числу прибавляется единица, далее к результату дописывается знаковый разряд, равный единице.
В качестве примера переведём число [math] -5 [/math] в дополнительный восьмибитный код. Прямой код модуля [math] -5 [/math] : [math] 0000101 [/math] , обратный — [math] 1111010 [/math] , прибавляем [math] 1 [/math] , получаем [math] 1111011 [/math] , приписываем [math] 1 [/math] в качестве знакового разряда, в результате получаем [math] 11111011 [/math] .
Также дополнительный код отрицательного числа [math] A [/math] , хранящегося в [math] n [/math] битах, равен [math] 2^n — |A| [/math] . По сути, дополнительный код представляет собой дополнение [math] |A| [/math] до [math] 0 [/math] : так как в [math] n [/math] -разрядной арифметике [math] 2^ = 0 [/math] (двоичная запись этого числа состоит из единицы и [math] n [/math] нулей, а в [math] n [/math] -разрядную ячейку помещаются только [math] n [/math] младших разрядов, то есть [math] n [/math] нулей), то верно равенство [math] 2^n — |A| + |A| = 0 [/math] .
Для получения из дополнительного кода самого числа нужно инвертировать все разряды кода и прибавить к нему единицу. Можно проверить правильность, сложив дополнительный код с самим числом: результат должен быть равен [math] 2^n [/math] . Переведём [math] 11111011 [/math] обратно. Инвертируем — [math] 00000100 [/math] , прибавляем [math] 1 [/math] , получаем [math] 00000101 [/math] — модуль исходного числа [math] -5 [/math] . Проверим: [math] 11111011 + 00000101 = 100000000 [/math] .
Можно получить диапазон значений [math] [-2^; 2^ — 1] [/math] .
Длинная арифметика для чисел, представленных с помощью кода с дополнением до двух
Дополнительный код также удобно использовать для вычислений в длинной арифметике, особенно для операций сложения и вычитания. Это операции удобно выполнять с числами одинаковой длины, поэтому в старшие разряды меньшего числа нужно поместить нули (если число положительно) или единицы (если число отрицательно). Тогда числа будут выглядеть следующим образом: в старших разрядах бесконечное число нулей (единиц), а в младших разрядах уже встречаются и нули, и единицы, которые кодируют само число, а не знак. Удобство заключается в том, что нам не обязательно проделывать операции сложения с каждой парой бит, если мы знаем, что на этом отрезке в числах стоят либо единицы, либо нули. Таким образом, на этом отрезке в получившемся числе тоже будут либо только единицы, либо только нули. Операцию сложения можно выполнить только один раз для старших битов, таким образом мы узнаем знак получившегося числа. Вычитание тоже выполняется просто: инвертируем число, прибавляем один и получаем это число с минусом, затем просто делаем сложение. Однако умножение с числами, представленными дополнительным кодом, выполнять не всегда оптимально: алгоритм либо слишком медленный (наивный алгоритм работает за [math]O(n^2)[/math] ), либо слишком сложный. Лучше для умножение использовать прямой код (бит под знак). Тогда можно числа перевести в десятичную систему счисления, выполнить быстрое преобразование Фурье за [math]O(n \log n)[/math] , затем перевести их обратно в двоичную. Обычно такой алгоритм работает быстрее, чем выполнение операции напрямую с двоичными числами. Для деления обычно тоже лучше использовать прямой код.
Достоинства представления чисел с помощью кода с дополнением до двух
- Возможность заменить арифметическую операцию вычитания операцией сложения и сделать операции сложения одинаковыми для знаковых и беззнаковых типов данных, что существенно упрощает архитектуру процессора и увеличивает его быстродействие.
- Нет проблемы двух нулей.
Недостатки представления чисел с помощью кода с дополнением до двух
- Ряд положительных и отрицательных чисел несимметричен, но это не так важно: с помощью дополнительного кода выполнены гораздо более важные вещи, желаемые от способа представления целых чисел.
- В отличие от сложения, числа в дополнительном коде нельзя сравнивать как беззнаковые, или вычитать без расширения разрядности.
Несмотря на недостатки, дополнение до двух в современных вычислительных системах используется чаще всего.
См. также
- Представление вещественных чисел
- Представление символов, таблицы кодировок
Источники информации
- Эндрю Таненбаум «Архитектура компьютера», 5-е изд., стр. 739—741
- Wikipedia — Signed number representations
- Wikipedia — Offset binary
- Википедия — Прямой код
- Википедия — Дополнительный код
Сложение положительного и отрицательного числа в двоичной системе исчисления
Язык программирования c# Заданы положительное и отрицательное число в двоичной сс (последовательность нулей и единиц). Составить программу вычисления суммы двух чисел.
public class HelloWorld < public static void Main(string[] args) < string str1 = Console.ReadLine(); string str2 = Console.ReadLine(); Console.WriteLine(dec_to_bin(bin_to_dec(str1)+bin_to_dec(str2))); Console.ReadKey(); >static Int32 bin_to_dec(string a) < double b = 0; for (double i = a.Length - 1; i >= 0; i--) b += Convert.ToDouble(a.Substring(Convert.ToInt16(i), 1)) * Math.Pow(2, i); return Convert.ToInt32(b); > static string dec_to_bin(Int32 a) < string b = ""; while (a != 0) < b = (Convert.ToInt16(a % 2)).ToString() + b; a /= 2; >return b; > >
Я написала этот код, но раньше никогда не сталкивалась с отрицательными числами в двоичной сс, я хочу понять правильно ли написан мой код и если есть ошибки помогите пожалуйста исправить их.