Представление чисел в обратном коде: перевод и формула

Обратный код (ones complement) - один из трёх школьных и вузовских способов хранить знак целого числа в двоичной записи, наряду с прямым и дополнительным кодом. Идея простая: положительные числа записываются как обычно, а у отрицательного числа инвертируют (меняют на противоположные) все разряды, кроме знакового. Это промежуточный шаг к дополнительному коду, которым реально пользуются процессоры, но именно на обратном коде удобнее всего понять, откуда берётся правило «прибавить единицу» и почему у нуля в такой арифметике целых два представления. Ниже разберём точную формулу перевода, диапазон значений и то, как в обратном коде складывают числа - через циклический (end-around) перенос. Покрути калькулятор ниже: он показывает прямой и обратный код по разрядам, а в режиме сложения - сам перенос из знакового разряда обратно в младший.
Зачем нужен обратный код
Самый наивный способ хранить знак - прямой код: взять двоичную запись модуля числа и добавить впереди один разряд-флаг (0 - плюс, 1 - минус). У прямого кода сразу два неудобства. Во-первых, ноль получает два разных представления: (+0) и (−0), которые формально различаются, хотя по смыслу это одно и то же число. Во-вторых, для сложения разнознаковых чисел в прямом коде нужна отдельная схема вычитания - нельзя просто сложить разряды столбиком, как для положительных чисел.
Обратный код решает вторую проблему лишь частично: сложение уже можно делать обычным двоичным сложением, но с оговоркой про перенос из старшего разряда (см. ниже), а два представления нуля остаются. Именно поэтому в реальных процессорах используется дополнительный код - но обратный код исторически и методически важен: он показывает, что «отрицательное число» - это просто другой двоичный узор, полученный по чёткому правилу, а не какая-то особая сущность.
Как перевести число в обратный код
Правило перевода короткое. Пусть разрядность слова - бит, старший разряд - знаковый.
- Если число , обратный код совпадает с прямым: знаковый разряд 0, а остальные разрядов - обычная двоичная запись .
- Если , знаковый разряд становится 1, а все разрядов модуля инвертируются: каждый 0 меняется на 1, а каждая 1 - на 0.
Есть и более компактная формулировка того же правила: обратный код отрицательного числа - это дополнение модуля числа до «всех единиц». Если - то число, которое получится, если прочитать все разрядов обратного кода как обычное беззнаковое двоичное число, то
Возьмём при : модуль , а . Тогда , что в двоичной записи даёт - это и есть обратный код числа в 8 битах. Прямой код того же числа - : сравните разряды и увидите, что все семь младших разрядов действительно инвертированы, а знаковый остался 1.
Диапазон значений и два нуля
Обратный код с -битным словом хранит только разряд под модуль числа, поэтому диапазон значений симметричный:
Для 8 бит это от до , для 4 бит - от до , для 16 бит - от до . Симметрия - прямое следствие того, что оба крайних кода, и , кодируют одно и то же значение - ноль: «плюс ноль» и «минус ноль».

Наличие двух нулей - не просто теоретическая странность: при сравнении кодов на равенство нулю схема должна проверять оба варианта, а свободный код означает, что из возможных комбинаций разрядов используется только различное значение. Это одна из причин, по которой обратный код не стал стандартом для процессоров.
Сложение чисел в обратном коде: циклический перенос
Главное практическое умение с обратным кодом - сложение с учётом циклического (по-другому - «сквозного», end-around) переноса. Алгоритм такой:
- Перевести оба числа в обратный код разрядностью бит.
- Сложить оба кода как обычные беззнаковые двоичные числа разрядностью бит.
- Если при сложении возник перенос из старшего (знакового) разряда за пределы разрядной сетки - этот перенос не отбрасывается, а прибавляется обратно к младшему разряду результата.
- Полученные разрядов - обратный код суммы; декодировать его обратно в десятичное число можно по той же формуле, что и одиночное число.
Разберём на числах и при . Обратный код - , обратный код - . Их сумма как беззнаковых 8-битных чисел даёт девять значащих разрядов: . Девятый (лишний) разряд - это и есть циклический перенос: его отбрасываем из разрядной сетки, но прибавляем единицей к оставшимся восьми разрядам:
Декодируем результат: знаковый разряд 1, значит это отрицательное число, а беззнаковое значение всей строки равно . По формуле - ровно то, что мы и ожидали от .
Важная оговорка: если оба слагаемых одного знака, а знак результата после переноса получился другим - это переполнение, а не корректный ответ. Обратный код (как и любой -битный формат) не может представить сумму, которая по модулю превышает .
Точно так же, только по другому правилу переноса, устроено сложение в дополнительном коде - там лишний перенос из старшего разряда просто отбрасывается без обратного прибавления, а диапазон уже несимметричный ( до ), потому что у нуля остаётся только одно представление.
Обратный код и дополнительный код: в чём разница
Обратный код и дополнительный код почти всегда путают, потому что дополнительный код получается из обратного добавлением единицы: (для отрицательных чисел). Из-за этой единицы у дополнительного кода нет второго представления нуля, а перенос из старшего разряда при сложении можно просто отбрасывать - никакого циклического возврата не требуется. Обратный код проще для понимания «инвертировали разряды - и готово», но платит за эту простоту двумя нулями и дополнительным шагом при сложении.
Частые ошибки
- Инвертирование знакового разряда. В обратном коде знаковый разряд отрицательного числа остаётся 1, инвертируются только оставшиеся разрядов модуля.
- Забытый циклический перенос. Если при сложении обратных кодов возник перенос из старшего разряда, его нельзя просто отбросить - он обязан вернуться в младший разряд результата.
- Путаница с дополнительным кодом. Правило переноса разное: в обратном коде перенос прибавляется обратно, в дополнительном - отбрасывается без остатка.
- Игнорирование двух нулей. Код - это тоже ноль (−0), а не «минус самое маленькое число».
- Проверка на переполнение по знакам. Если оба слагаемых одного знака, а знак суммы после переноса получился другим - это переполнение, результат недостоверен.
FAQ
Чем обратный код отличается от прямого? В прямом коде отрицательное число - это просто модуль с флагом знака 1 в старшем разряде, остальные разряды не меняются. В обратном коде дополнительно инвертируются все разряды модуля, кроме знакового.
Как декодировать обратный код без ручного инвертирования битов? Прочитайте все разрядов как беззнаковое число . Если - это и есть искомое число. Если - искомое число равно и оно отрицательное.
Почему у нуля два представления именно в обратном коде? Код из одних нулей даёт , то есть («плюс ноль»). Код из одних единиц даёт , а по формуле это тоже («минус ноль»). Оба кода законны по правилу перевода и оба декодируются в один и тот же ноль - отсюда и двойственность. Дополнительный код убирает её за счёт добавленной единицы.
Коротко
Обратный код хранит отрицательное число как дополнение его модуля до «всех единиц» разрядной сетки: , знаковый разряд при этом равен 1, а остальные разряды модуля инвертированы. Диапазон значений симметричен - от до , а ноль представлен двумя разными кодами. При сложении чисел в обратном коде перенос из старшего разряда не отбрасывается, а возвращается в младший разряд - это и называют циклическим переносом. Именно ради избавления от двух нулей и лишнего шага сложения на практике перешли на дополнительный код.
Читайте также

Дополнительный код: представление отрицательных чисел
Как работает дополнительный код в двоичных системах: диапазон значений, перевод отрицательного числа, разбор по весам разрядов, переполнение и типичные ошибки в задачах.

Формула Хартли: как посчитать количество информации
Формула Хартли простыми словами: как посчитать количество информации через число равновероятных исходов, зачем округлять log2(N) вверх и как найти объём сообщения по мощности алфавита.

Построение логической схемы по выражению: алгоритм
Как построить логическую схему по логическому выражению: порядок сборки элементов И, ИЛИ, НЕ по приоритету операций, обозначения ГОСТ и разбор частых ошибок студентов.

Кодирование текста в ASCII: коды, биты и объём
Как работает кодирование текста в ASCII: что такое код символа, как перевести букву в двоичный и шестнадцатеричный вид, сколько бит и байт занимает строка и чем ASCII отличается от Unicode.

Дополнительный код: представление отрицательных чисел
Дополнительный код простыми словами: как записать отрицательное число в двоичном виде, почему старший бит весит со знаком минус, как перевести число в код и обратно и где возникает переполнение.

Атрибуты сущности в ER-модели: пять типов и примеры
Разбираем пять типов атрибутов сущности в ER-модели: простой, составной, ключевой, многозначный, производный, с примерами и переходом к столбцам и таблицам реляционной схемы.