EssayAI
Блог
Блог
Естественные науки

Дополнительный код: представление отрицательных чисел

11 июня 2026Время чтения: 7 минут
#дополнительный код#отрицательные числа#двоичная система#переполнение#разрядность

Дополнительный код (two's complement) - это способ записывать целые числа со знаком в двоичной системе так, чтобы вычитание превращалось в обычное сложение, а одна и та же схема сумматора работала и с положительными, и с отрицательными числами. Именно поэтому почти все процессоры хранят знаковые целые именно в дополнительном коде, а не в прямом или обратном. Ниже разберём, как записать отрицательное число в фиксированной разрядности, почему старший разряд получает отрицательный вес, как переводить число в код и обратно тремя способами и где в задачах возникает переполнение. Чтобы сразу почувствовать связь между числом и его битами, покрути калькулятор ниже: он показывает дополнительный код в двоичном и шестнадцатеричном виде, вклад каждого разряда и положение числа на кольце кодов.

Зачем нужен дополнительный код

В прямом коде знак числа хранится в старшем бите: 0 - плюс, 1 - минус, а остальные разряды задают модуль. Просто, но неудобно: появляются два нуля (положительный и отрицательный), а вычитание требует отдельной логики сравнения знаков. Дополнительный код избавляется от обоих недостатков. В нём отрицательное число записывается так, что его сложение с положительным даёт правильный результат на том же сумматоре, который складывает беззнаковые числа. Ноль остаётся единственным, а диапазон используется полностью.

Главная идея: при фиксированной разрядности NN бит все коды живут по модулю 2N2^N. Отрицательное число xx представляется тем же кодом, что и беззнаковое 2N+x2^N + x. Например, в 8 битах число 1-1 кодируется как 281=2552^8 - 1 = 255, то есть все восемь единиц. Поэтому при переборе кодов от 00 вверх мы доходим до максимума, а затем «переваливаем» в отрицательную область - отсюда и образ кольца.

Счётчик идёт по 4-битному кольцу кодов: 0, 1, 2 ... 7, а затем 1000 переключается на значение -8 и счёт продолжается -7, -6 ... -1, после чего возвращается к 0. Видно, как старший бит переключает знак

Как старший бит получает отрицательный вес

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

x=bN12N1+k=0N2bk2k,x = -b_{N-1}\cdot 2^{N-1} + \sum_{k=0}^{N-2} b_k\cdot 2^{k},

где bkb_k - значение kk-го бита. Все младшие разряды дают привычные положительные веса 20,21,,2N22^0, 2^1, \dots, 2^{N-2}, и только старший разряд bN1b_{N-1} весит 2N1-2^{N-1}. Если он равен нулю, число положительно и совпадает с беззнаковым; если единице - к сумме добавляется большое отрицательное слагаемое, и число уходит в минус.

Возьмём канонический пример: 8-битный код 1101001111010011. Старший бит равен 1, значит вклад старшего разряда 27=128-2^7 = -128. Остальные единицы стоят в разрядах 6, 4, 1 и 0, давая 64+16+2+1=8364 + 16 + 2 + 1 = 83. Итог: 128+83=45-128 + 83 = -45. Тот же код, прочитанный как беззнаковое число, равен 211211, а в шестнадцатеричной записи это 0xD30xD3.

Веса разрядов 8-битного числа: старший разряд подписан как минус 128, остальные как 64, 32, 16, 8, 4, 2, 1, активные биты выделены
Веса разрядов 8-битного числа: старший разряд подписан как минус 128, остальные как 64, 32, 16, 8, 4, 2, 1, активные биты выделены

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

Как перевести число в дополнительный код

Для отрицательного числа есть три эквивалентных пути, и в калькуляторе они дают один и тот же результат.

Первый - по формуле остатка. Код отрицательного числа xx равен беззнаковому представлению величины 2Nx2^N - |x|. Для x=45x = -45 и N=8N = 8 это 25645=211256 - 45 = 211, то есть 11010011211010011_2.

Второй - инверсия и плюс единица, самый удобный «ручной» способ. Записываем модуль числа в обычном двоичном виде, инвертируем все биты (получаем обратный код), затем прибавляем единицу:

45=001011012  инверсия  110100102  +1  110100112.45 = 00101101_2 \;\xrightarrow{\text{инверсия}}\; 11010010_2 \;\xrightarrow{+1}\; 11010011_2.

Третий - через подбор по весам: подобрать единицы в разрядах так, чтобы их веса (с отрицательным старшим) дали нужное число. На практике им пользуются для проверки, а не для расчёта.

Перевод -45 в дополнительный код: модуль 00101101, инверсия 11010010, прибавление единицы дает 11010011
Перевод -45 в дополнительный код: модуль 00101101, инверсия 11010010, прибавление единицы дает 11010011

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

Диапазон представимых чисел и его несимметричность

При NN битах в дополнительном коде помещаются числа от 2N1-2^{N-1} до 2N112^{N-1}-1:

2N1x2N11.-2^{N-1} \le x \le 2^{N-1}-1.

Для 8 бит это от 128-128 до 127127, для 16 бит - от 32768-32768 до 3276732767. Диапазон несимметричен: отрицательных чисел на одно больше, чем положительных. Причина проста - один из 2N2^N кодов занят нулём, и он лежит в «положительной» половине, поэтому самому большому по модулю отрицательному числу 2N1-2^{N-1} нет положительной пары. Отсюда известная ловушка: модуль числа 128-128 в 8 битах нельзя представить как +128+128, а попытка взять (128)-(-128) снова даёт 128-128.

Сложение, вычитание и переполнение

Главная награда за дополнительный код - арифметика. Чтобы вычесть, достаточно прибавить дополнительный код вычитаемого: ab=a+(код(b))a - b = a + (\text{код}(-b)). Перенос из старшего разряда просто отбрасывается, потому что вычисления идут по модулю 2N2^N. Это и позволяет одному сумматору обслуживать оба знака.

Опасность одна - переполнение. Оно возникает, когда истинный результат выходит за диапазон [2N1,2N11][-2^{N-1},\, 2^{N-1}-1]. Признак переполнения: при сложении двух чисел одного знака получился результат противоположного знака. Например, в 8 битах 100+50=150100 + 50 = 150, но 150>127150 > 127, поэтому код «перескакивает» через границу и читается как 150256=106150 - 256 = -106. Программный или аппаратный флаг переполнения как раз ловит ситуацию, когда перенос в старший разряд и перенос из него не совпадают.

Частые ошибки

  • Инверсия без прибавления единицы. После инвертирования битов получается обратный код, а не дополнительный. Единицу прибавлять обязательно, иначе число будет меньше на единицу.
  • Игнорирование разрядности. Дополнительный код не существует «вообще»: 1-1 - это 11111111 в 4 битах и 1111111111111111 в 8 битах. Без указания NN запись бессмысленна.
  • Перевод старшего бита как обычного. Старший разряд весит 2N1-2^{N-1}, а не +2N1+2^{N-1}. Если прочитать его с плюсом, отрицательные числа превратятся в большие положительные.
  • Симметричный диапазон. Граница не ±2N1\pm 2^{N-1}, а от 2N1-2^{N-1} до 2N112^{N-1}-1. Число 2N1-2^{N-1} есть, а его положительной пары нет.
  • Незамеченное переполнение. Отброшенный перенос - это норма, а вот смена знака при сложении одинаковых знаков - сигнал, что результат недостоверен.

FAQ

Как перевести отрицательное число в дополнительный код вручную? Запишите модуль числа в двоичном виде в нужной разрядности, инвертируйте все биты и прибавьте единицу. Для 45-45 в 8 битах: 45=0010110145 = 00101101, инверсия 1101001011010010, плюс единица - 1101001111010011.

Почему старший бит называют знаковым, если у него есть и вес? Потому что он одновременно указывает знак и вносит вклад 2N1-2^{N-1} в значение. У положительных чисел он равен нулю, у отрицательных - единице, но это не отдельный флаг, а полноценный разряд с отрицательным весом.

Чем дополнительный код лучше прямого и обратного? В нём единственный ноль и не нужна отдельная логика для вычитания: оно сводится к сложению. Прямой и обратный коды дают два нуля и требуют коррекции при переносе, поэтому в процессорах прижился именно дополнительный код.

Коротко

Дополнительный код представляет знаковые целые так, что вычитание становится сложением, а старший разряд весит 2N1-2^{N-1}. Отрицательное число получают по формуле 2Nx2^N - |x| или инверсией битов модуля с прибавлением единицы; обратное чтение - это сумма по весам разрядов. Диапазон при NN битах равен от 2N1-2^{N-1} до 2N112^{N-1}-1 и несимметричен, а выход за него даёт переполнение, заметное по неожиданной смене знака.

Доверьте текст нейросети EssayAI

Открыть EssayAI

Бесплатно, на русском языке и без VPN

Читайте также