Altifigence Academy

8 / 37 · Теория

Дополнительный код, расширение знака и переполнение

Различайте знаковую интерпретацию битовой строки и условия переполнения сложения с помощью формул и контрпримеров.

Вес старшего бита меняется

NN-битное целое в дополнительном кодеДополнительный код представляет знаковые целые битовой последовательностью фиксированной ширины. Для n бит диапазон составляет от −2^(n−1) до 2^(n−1)−1. интерпретируется так:

s=−bN−12N−1+∑i=0N−2bi2is=-b_{N-1}2^{N-1}+\sum_{i=0}^{N-2}b_i2^i
−2N−1≤s≤2N−1−1-2^{N-1}\le s\le 2^{N-1}-1

Четырёхбитное 1010 означает 10 как unsignedБеззнаковая интерпретация (unsigned) рассматривает битовую последовательность как неотрицательное целое. Диапазон n бит — от 0 до 2^n−1; знаковая интерпретация тех же битов может дать другое число. Подробнее и −6 как signed. Это не схема «отделить знаковый бит, оставшееся прочитать как модуль». При фиксированной ширине −x-x получают инверсией битовИнверсия — операция NOT, меняющая 0 на 1 и 1 на 0. Черта над формулой означает применение NOT ко всему выражению под ней. Подробнее и добавлением 1, но положительное +8 для минимального −8 не входит в тот же 4-битный signed-диапазон.

Расширение должно сохранять значение

Unsigned расширяют нулями слева, signed — копиями исходного знакового бита. Превращение 1010 в 00001010 даёт +10, в 11111010 — −6. Даже расширение одинаковых битов требует разных схем при разной интерпретации.

SystemVerilog
logic signed [3:0] a, b;
logic signed [4:0] exact;
logic [3:0] result;
logic overflow;
assign exact = {a[3], a} + {b[3], b};
assign result = exact[3:0];
assign overflow = (a[3] == b[3]) && (result[3] != a[3]);

В примере складываются два знаковых операнда без carry на входе. В exact сохраняется 5-битная сумма, затем проверяется правильность знака суженного результата.

Начальное значение — 11111010. Убедитесь, что unsigned 250 и signed −6 представлены одними битами. Изменение b7 меняет значения двух интерпретаций в разных направлениях.

Как читать знак одних и тех же восьми битов

11111010 → unsigned 250 · signed -6 · hex 0xFA

Carry и знаковое переполнение различаются

V=aN−1⊕bN−1‾ (sN−1⊕aN−1)V=\overline{a_{N-1}\oplus b_{N-1}}\,(s_{N-1}\oplus a_{N-1})

Если при сложении чисел одного знака знак результата изменился, произошло переполнение. В 4 битах 7+37+3 сохраняется как 1010, выглядя как −6, а −8+(−1)-8+(-1) — как 0111, выглядя как +7. При сложении двух чисел разных знаков такого выхода за диапазон не возникает.

Смешение signed и unsigned в RTL усложняет правила сравнения и расширения. Явно задавайте ширину и знаковость обоих операндов, включайте в граничные тесты минимум, −1, 0 и максимум.

Попробуйте сами

Для 4-битных signed найдите сохранённые биты и overflow в −3+(−4)-3+(-4) и 5+55+5. Объясните также результат отрицания −8-8.

Прочитать объяснение

−7-7 представляется как 1001, переполнения нет. 10 выходит за диапазон и сохраняется как 1010 (−6), поэтому overflow есть. Инверсия −8 с добавлением 1 снова оставляет 1000: +8 в этом диапазоне не представимо. Нельзя использовать это как корректное вычисление модуля числа.

Выбор действует в этом браузере. Его можно изменить внизу страницы.