Altifigence Academy

8 / 37 · 概念

2 の補数・符号拡張・オーバーフロー

式と反例を使い、ビット列の signed 解釈と加算のオーバーフロー条件を区別します。

最上位ビットの重みが変わります

NN ビットの 2 の補数2 の補数 固定幅のビット列で符号付き整数を表す方式です。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

4 ビットの 1010 は unsignedunsigned ビット列を非負整数として解釈する規則です。n ビットの範囲は 0 から 2^n−1 で、同じビット列の signed 解釈と異なる場合があります。 詳しく見る で 10、signed で -6 です。符号ビットを除いた残りを絶対値として読む方式ではありません。固定幅で −x-x を作るにはビット否定否定 0 を 1 に、1 を 0 に変える NOT 演算です。式の上の線は、その下の式全体に NOT を適用することを表します。 詳しく見る後に 1 を加えますが、最小値 -8 に対応する正の +8 は同じ 4 ビット signed の範囲外です。

拡張は値を保存しなければなりません

unsigned の拡張では上位に 0、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]);

この例はキャリー入力のない二オペランドの符号付き加算です。exact に 5 ビットの和を保存し、幅を狭めた結果の符号が正しいか検査します。

初期値を 11111010 にしています。unsigned の 250 と signed の −6 が同じビット列であることを確認してください。b7 を変えると、二つの解釈で値が逆方向に変わります。

同じ 8 ビットの符号解釈

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

キャリーと符号付きオーバーフローは異なります

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 で −3+(−4)-3+(-4) と 5+55+5 の格納ビット列とオーバーフローを求めてください。−8-8 の符号を反転した結果も説明してください。

解説を見る

−7-7 は 1001 で、オーバーフローはありません。10 は範囲外で 1010(-6)として格納されるため、オーバーフローです。-8 をビット反転して 1 を加えると、再び 1000 が残ります。+8 を表せないためで、これを正しい絶対値計算として使ってはいけません。

選択はこのブラウザに適用されます。フッターからいつでも変更できます。