2進数で負の数を表す3つの方法 ― 絶対値表現・1の補数表現・2の補数表現

広告

コンピュータは数値をすべて0と1のビット列で扱う。正の数はそのまま2進数に変換すればよいが、負の数をどう表現するかは一つに決まっているわけではなく、歴史的に複数の方式が使われてきた。本記事では代表的な3方式「絶対値表現(符号+絶対値表現)」「1の補数表現」「2の補数表現」を、8ビットの例を使って比較する。

前提:8ビットで考える

以下ではすべて8ビット(1バイト)の符号付き整数を例にする。最上位ビット(MSB)を符号ビットとして使う点は3方式に共通している。

  • 符号ビットが 0 → 正の数
  • – 符号ビットが 1 → 負の数

この後、+5 と -5 を例に、各方式でのビット表現を見ていく。

+5 の絶対値は 2進数で 0000101 なので、8ビットにすると次のようになる。

+5 = 00000101

  1. 絶対値表現(符号+絶対値表現)

最もシンプルな方式。最上位ビットを符号(0=正、1=負)とし、残りのビットに数の絶対値をそのまま入れる。

+5 = 00000101 (符号0 + 絶対値0000101)

-5 = 10000101 (符号1 + 絶対値0000101)

正の数と負の数は符号ビットが違うだけで、絶対値部分は完全に同じという分かりやすさが利点。

問題点

ゼロが2通りできる。

+0 = 00000000

-0 = 10000000

回路やソフトウェアは +0 と -0 を別物として扱わないよう特別な配慮が必要になり、比較演算が煩雑になる。

普通の2進加算がそのまま使えない。

例えば 5 + (-3) を計算したい場合、絶対値表現のビット列同士を単純に加算しても正しい答えにならない。

00000101 (+5)

+ 10000011 (-3)




10001000 ← これは “-8" に見えるが、正しい答えは +2

符号を見て「同符号なら絶対値を足す」「異符号なら絶対値を引いて大きい方の符号をつける」という条件分岐をハードウェアで実装する必要があり、加算器の設計が複雑になる。

表現できる範囲(8ビットの場合):-127 ~ +127(ゼロの重複がある分、1の補数表現と同じく1個少ない)

2. 1の補数表現

負の数を「対応する正の数の全ビットを反転(0と1を入れ替える)したもの」として表す。

+5 = 00000101

-5 = 11111010 (00000101 の各ビットを反転)

「反転するだけ」という単純さが利点で、絶対値表現よりは加算のハードウェアがシンプルになる。

問題点

やはりゼロが2通りできる。

+0 = 00000000

-0 = 11111111

加算に「エンドアラウンドキャリー」という補正が必要。

00000101 (+5)

+ 11111010 (-5)




11111111 ← 桁上げが出ないケースはそのままだと “-0"

繰り上がり(キャリー)が最上位から出た場合、それを最下位ビットに足し戻す(エンドアラウンドキャリー)という追加処理をしないと正しい結果にならない場合がある。これも回路の複雑化につながる。

表現できる範囲(8ビットの場合):-127 ~ +127

3. 2の補数表現

現在ほぼすべてのコンピュータで採用されている方式。負の数を「1の補数表現にさらに1を足したもの」として定義する。

+5 = 00000101

11111010 ← まず全ビット反転(1の補数)

+ 1

———

-5 = 11111011 ← これが2の補数表現

もう少し実務的な求め方としては、「最下位ビットから見て、最初の1が立っているビットまではそのまま、それより上のビットをすべて反転する」というやり方もよく使われる。

利点

ゼロがただ1通りしかない。

0 = 00000000

11111111 は「ゼロ」ではなく「-1」を表す数として使われるため、無駄なビットパターンが出ない。

普通の加算器でそのまま引き算・負の数の演算ができる。

00000101 ( +5)

+ 11111011 ( -5)




00000000 ( 0) ※最上位からの桁上げは単純に捨ててよい

エンドアラウンドキャリーのような補正が不要で、繰り上がりを単純に無視するだけで正しい答えになる。これはCPUの加算回路をそのまま減算にも流用できることを意味し、ハードウェアの設計が大幅に単純化される。

00000101 ( +5)

+ 11111101 ( -3)




1 00000010 → 桁あふれ分(最上位からの繰り上がり)は捨てる → 00000010 = +2

表現できる範囲(8ビットの場合):-128 ~ +127

正の数の個数より負の数の個数が1つ多いという非対称性があるが、これはゼロの表現が1通りしかないことの裏返しであり、実用上ほとんど問題にならない。

3方式の比較

項目 | 絶対値表現 | 1の補数表現 | 2の補数表現

-5 の8ビット表現 | 10000101 | 11111010 | 11111011

ゼロの表現 | +0/-0 の2通り | +0/-0 の2通り | 0 の1通り

8ビットでの範囲 | -127 ~ +127 | -127 ~ +127 | -128 ~ +127

加算・減算の回路 | 符号判定が必要で複雑 | エンドアラウンドキャリーが必要 | そのまま加算するだけで良い

現在の実用状況 | ほぼ使われない | ほぼ使われない | ほぼすべてのCPUで採用

なぜ2の補数表現が主流になったのか

理由はシンプルで、加算回路だけで足し算も引き算も処理できるからである。CPUにとって回路が単純であることは、コストの低さ・速度・消費電力に直結する。ゼロの表現が1通りしかない点も、比較命令や条件分岐のロジックを単純にする。

こうした理由から、現在使われているほぼすべてのプロセッサ(x86、ARMなど)は整数の負数表現に2の補数表現を採用している。基本情報技術者試験などでもこの3方式の違い、特に「2の補数がなぜ選ばれているか」はよく問われるポイントなので、実際にビット計算をして手を動かして確認しておくと理解が定着しやすい。

まとめ

絶対値表現:符号ビット+絶対値。直感的だが、ゼロの重複と加減算の複雑さが弱点。

1の補数表現:全ビット反転で負数を作る。絶対値表現よりは扱いやすいが、ゼロの重複とエンドアラウンドキャリーの問題が残る。

2の補数表現:1の補数に1を加えたもの。ゼロが1通りになり、加算器だけで減算も実現できるため、現代のコンピュータで標準的に採用されている。

訪問数 3 回, 今日の訪問数 4回

広告

C#

Posted by hidepon