2の補数を理解する (1)

昔、2の補数を理解できずに悩んだのを思い出したので、2の補数について書いてみたいと思います。
次回: id:simply-k:20100825:1282743815

1の補数と2の補数

1の補数

2の補数を理解する準備として、1の補数について説明します。ある数Aに対する1の補数とは、次のような条件を満たす数のことです。「『A』の2進表現と『Aの1の補数』の2進表現を加算すると、計算結果の全てのビットが1になる。」
例えば、Aの2進表現(8ビット)が01011100だった場合、Aの1の補数の2進表現は、10100011となります。(01011100 + 10100011 = 11111111) 例を見ればすぐにわかるように、Aの1の補数は、Aの2進表現をビット反転させたものになります。「オール1にするために補う数」なので、「1の補数」と呼ばれます。

2の補数

ある数Aに対する2の補数とは、次のような条件を満たす数のことです。「『A』の2進表現と『Aの2の補数』の2進表現を加算すると、計算結果は2nになる。(nはAのビット数)」
例えば、Aの2進表現(8ビット)が01011100だった場合、Aの2の補数の2進表現は、10100100となります。(01011100 + 10100100 = 100000000 = 28) 定義からすぐにわかるように、Aの2の補数は、Aの1の補数に1を足した値となります。1の補数はビット反転で計算できるため、2の補数は「ビット反転+1」で計算できることになります。「2nにするために補う数」なので、「2の補数」と呼ばれます。

1の補数と2の補数についての補足

1の補数や2の補数を考える場合、その数が何ビットで表現されるのかを意識する必要があります。例えば、10進数の5(2進数の101)に対する1の補数は、次のようになります。

  • 数値が4ビットで表現される場合は、0101をビット反転するので、1の補数は1010となる。
  • 数値が8ビットで表現される場合は、00000101をビット反転するので、1の補数は11111010となる。
  • 数値が16ビットで表現される場合は、0000000000000101をビット反転するので、1の補数は1111111111111010となる。

また、補数の定義から明らかなように、ある数の補数の補数は、元の数と一致します。つまり、次のような命題が成り足ります。

  • ある数Aに対し、Aの「1の補数」の「1の補数」はAである。
  • ある数Aに対し、Aの「2の補数」の「2の補数」はAである。
その他の補数

上記では2進数に関する補数を説明しましたが、それ以外の場合にも補数を考えることは可能です。例えば、10進数に対して、9の補数や10の補数を考えることが可能です。Aを4桁の10進数とします。ここで、Aの値が2345だったとすると、Aの9の補数は7654となります。(2345 + 7654 = 9999) また、Aの10の補数は7655となります。(2345 + 7655 = 10000 = 104)

符号付き整数と2の補数

符号付き整数を2の補数によって表現する

現在の一般的なコンピュータ環境では、符号付き整数を表現するために2の補数を利用します。2の補数を用いた符号付き整数の表現には、次のようなルールがあります。

  • 最上位ビットが1の場合は負の数、それ以外は0または正の数を表現する。
  • 負の数は、絶対値の2進表現の2の補数によって表現される。

これだけでは理解しにくいと思いますので、4ビットの場合について、表にしてみます。

2進表現 10進表現
(符号無し)
10進表現
(符号付き)
1111 15 -1
1110 14 -2
1101 13 -3
1100 12 -4
1011 11 -5
1010 10 -6
1001 9 -7
1000 8 -8
0111 7 7
0110 6 6
0101 5 5
0100 4 4
0011 3 3
0010 2 2
0001 1 1
0000 0 0

最上位ビットが1の数は、符号無しの場合には、表現可能な整数の中の大きい方の半分を表現します。しかし、符号付きの場合には、負の数を表現します。

2進表現での2の補数を計算することは、10進表現(符号付き)で符号を反転することに相当します。例えば、10進数の3と-3は2進数ではそれぞれ0011と1101ですが、ここで次のような対応が存在します。

  • 3 ← 符号を反転 → -3 (10進表現)
  • 0011 ← 2の補数を計算 → 1101 (2進表現)
2進表現から10進表現(符号付き)を求める方法

2進表現から10進表現(符号付き)を求める場合は、以下のようにして考えます。

  • 最上位ビットが0の場合は、単純に2進数を10進数に変換する。
    (例: 0110 → 6)
  • 最上位ビットが1の場合は、2の補数を10進数に変換し、符号としてマイナスを付ける。
    (例: 1100の2の補数は0100であり、「0100 → 4」である。つまり、「1100 → -4」である。)

最上位ビットが1の場合の計算では、ある数-Aの2進表現の2の補数がAになることを利用しています。

10進表現(符号付き)から2進表現を求める方法

10進表現(符号付き)から2進表現を求める場合は、以下のようにして考えます。

  • 0または正の数の場合は、単純に10進数を2進数に変換する。
    (例: 5 → 0101)
  • 負の数の場合は、絶対値の2進表現の2の補数に変換する。
    (例: -3の絶対値は3であり、「3 → 0011」である。0011の2の補数は1101なので、「-3 → 1101」である。)
表現可能な範囲

符号付き整数を2の補数によって表現する場合、表現可能な整数の範囲は、-(2n-1)〜2n-1-1(nはビット数)となります。例えば、8ビット整数の場合、表現可能な最小値は-128(-27)、最大値は127(27 - 1)となります。最大値の絶対値は、最小値の絶対値よりも1小さくなります。(最上位ビットが0の範囲に0が含まれるため)

補足

符号付き整数を2の補数によって表現する場合、次のような特徴があります。

  • 0(全ビット0)に対する2の補数は0になる。
  • 全ビット1は、-1を表現する。(何ビットで表現した場合でも同様)


次回は、2の補数を利用した整数の加算について説明します。
次回: id:simply-k:20100825:1282743815