Inuverse Sci. X Tech. Blog

← ブログ一覧

2の補数

#基本情報

まえおき

いちばんやさしい基本情報をよんだり、過去問道場で問題を解いていましたが、2の補数の存在意義がまったく感じられませんでした。

そこで何が嬉しいか考えてみてまとめたものがこの記事になります。 私の結論としては、0(10)0_{(10)}の表現をダブりなしで、一意的に表示できるため、2の補数を使っていて嬉しいと感じると思いました。

以下では、整数を表すのに2進数で8ビットの範囲で表現します。

一番左のビットで正数、負数を表現する

たとえば、100(10)100_{(10)}を考えてみましょう。これは64+32+4=26+25+2264 + 32 + 4 = 2^6 + 2^5 + 2^2なので、2進数で、

100(10)=01100100(2) 100_{(10)} = 0\vdots110\,0100_{(2)}

と表現されます。わかりやすさのために、一番左のビットを区別するため\vdotsを表示しています。

もっとも単純な負数の表現方法は、一番左のビットは正数、負数を表すフラグを与えると考え、それが00なら正数、11なら負数とルールを決めてしまうことです。

このルールに則れば、100(10)-100_{(10)}

100(10)=11100100(2) - 100_{(10)} = 1\vdots110\,0100_{(2)}

です。これなら、127-127まで表現できそうな気がします。

しかしながら実際はうまくいきません。なぜなら、このルールのまま足し算を実行すると、計算結果が破綻してしまうからです。実際にやってみましょう:

100(10)=01100100(2)+)100(10)=11100100(2)0(10)=01001000(2)(=72(10))\begin{array}{rl} 100_{(10)} &= 0\vdots110\,0100_{(2)} \\ +)\, -100_{(10)} &= 1\vdots110\,0100_{(2)} \\ \hline 0_{(10)} &= 0\vdots100\,1000_{(2)} (= 72_{(10)})\\ \end{array}

このように左辺と右辺の結果が合いません。よって、一番左のビットで正負を表現するだけではまだ足りなさそうです。

1の補数

絶対値が同じで、正負が異なる2つの数の足し算は0になることを念頭におくと、負数を表現するためにはビット反転を用いればよさそうな気がします。さっきの例と同様に100(10)100_{(10)}をもう一度使ってみると、

100(10)=01100100(2)+)100(10)=10011011(2)0(10)=11111111(2)\begin{array}{rl} 100_{(10)} &= 0\vdots110\,0100_{(2)} \\ +)\, -100_{(10)} &= 1\vdots001\,1011_{(2)} \\ \hline 0_{(10)} &= 1\vdots111\,1111_{(2)} \end{array}

となります。これを11111111(2)1\vdots111\,1111_{(2)}を0と定義すればいいのですが、そうすると、0には2つの表現方法00000000(2)0\vdots000\,0000_{(2)}11111111(2)1\vdots111\,1111_{(2)}の2つが存在してしまうことになります。

こうなるとコンピュータ上では、それぞれを比較するときに同じものとして扱うのか、条件分岐はどうするのか、など本質的ではない問題に立ち向かわなければなりません。

2の補数

ビット反転した数字に1を足した数字で負数を表現するというルールにしましょう。さっきの例と同様に100(10)100_{(10)}をもう一度使ってみると、

100(10)=01100100(2)+)100(10)=10011100(2)0(10)=00000000(2)\begin{array}{rl} 100_{(10)} &= 0\vdots110\,0100_{(2)} \\ +)\, -100_{(10)} &= 1\vdots001\,1100_{(2)} \\ \hline 0_{(10)} &= 0\vdots000\,0000_{(2)} \end{array}

となります。8桁より大きい桁はコンピュータ上では無視するので、想定する結果がでてくるようになりました!


← ブログ一覧