1. 補数とは何か
補数(complement)とは、ある数値に特定の数を加えると、桁上がりが発生するような数のことを指します。例えば、10進数で「3」に対する補数は「7」であり、これらを足すと「10」となり、一桁上がります。同様に、2進数で「011」に対する補数は「101」で、これらを足すと「1000」となり、桁上がりが生じます。
補数には、基数の補数(radix complement)と減基数の補数(diminished radix complement)の2種類があります。基数の補数は、与えられた数を基数のべき乗から引いた値で、減基数の補数は、基数のべき乗から1を引いた値から与えられた数を引いた値です。
1.1. JISの定義を確認する
補数(と関係する数)の定義についてJISで確認してみましょう。
補数(complement)は、「与えられた数を、ある決められた数から引くことによって得られる数」(JIS X0005)です。
基数の補数(radix complement)は、「与えられた数を、基数のある決められたべき乗から引くことによって得られる補数」(JIS X0005)です。
減基数の補数(diminished radix complement)は、「与えられた数を、基数のある決められたべき乗より1小さい数から引くことによって得られる補数」(JIS X0005)です。
2. 補数を式で表す
2.1. b進法
\(b\)進法で\(n\)桁の数字\(x\)の補数を考えます。
補数\(y\)は、定義にしたがって\(y = b^n – x\)となります。
減基数の補数\(z\)は、\(z = ( b^n – 1 ) – x\)となります。
2.2. 10進法
より具体的に10進法の場合で考えてみます。
2.2.1. 10の補数
10進法で3桁の数字321の補数を考えます。
補数は、\(y = 10^3 – 321 = 679\)
これは基数の補数ですので、321の10(10が基数)の補数となります。
基数の補数ですので、\(679 + 321 = 1000 = 10^3\)で、定義どおりだと確認できました。
2.2.2. 9の補数
減基数の補数は、\(z = ( 10^3 – 1 ) – 321 = 678\)
これは減基数の補数ですので、321の9(10の減基数)の補数となります。
減基数の補数ですので\(678 + 321 = 999 = 1000 – 1 = 10^3 – 1\)で、定義どおりです。
2.3. 2進法
2.3.1. 2の補数
2進法で3桁の数字111の補数を考えます。
補数は、\(y = 2^3 – 111 = 1\)
これは基数の補数ですので111の2(2が基数)の補数となります。
基数の補数ですので、\(1 + 111 = 1000 = 2^3\)で、定義どおりだと確認できました。
2.3.2. 1の補数
減基数の補数は、\(z = ( 2^3 – 1 ) – 111 = 0\)
これは減基数の補数ですので、321の1(2の減基数)の補数となります。
減基数の補数ですので\(0 + 111 = 111 = 1000 – 1 = 2^3 – 1\)で、定義どおりです。
3. 1の補数と2の補数
コンピュータで計算する場合、32bitや64bitという2進法で表現された2進数を用いて計算します。
この2進数は、論理演算という計算方法と親和性が良いためコンピュータには欠かせないものです。
そこで先にみてきた2進法での補数である1の補数と2の補数について見ていきましょう。
3.1. 1の補数の特徴
まず、1の補数がどのようなものか4bitの場合で見ていきます。
2進数 | 10進数 | 1の補数 | 1の補数の10進数 |
0000 | 0 | 1111 | -0 |
0001 | 1 | 1110 | -1 |
0010 | 2 | 1101 | -2 |
0011 | 3 | 1100 | -3 |
0100 | 4 | 1011 | -4 |
0101 | 5 | 1010 | -5 |
0110 | 6 | 1001 | -6 |
0111 | 7 | 1000 | -7 |
1000 | 8 | 0111 | 7 |
1001 | 9 | 0110 | 6 |
1010 | 10 | 0101 | 5 |
1011 | 11 | 0100 | 4 |
1100 | 12 | 0011 | 3 |
1101 | 13 | 0010 | 2 |
1110 | 14 | 0001 | 1 |
1111 | 15 | 0000 | 0 |
この表を見てわかるとおり、1の補数をとるというのは、各ビットを反転させることと同じです。そのためコンピュータで計算するのは高速に行えます。(ビット毎のnotをとる)
しかし、1の補数では0は0000と11111の2つの表現やキャリーオーバーの課題があり、使い場所は多くありません。
3.1.1. 1の補数のキャリーオーバーの例
先の4bitの数値で計算してみます。
A:1101(10進数の2)
B:1011(10進数の4)
これらを加算します。
1101 + 1011 = 1 1000
これは、キャリーオーバー:1、結果:1000という意味になります。
これを正しい結果にするためにはキャリーオーバーした1を最下位ビットに加える必要があります。
1000 + 0001 = 1001
この処理をおこなう必要があるため1の補数はあまり多くの場所では使われていません。
3.1.2. 1の補数の活用例
1の補数は、エラー検出のためのチェックサム計算に使用されることがあります。
Internet Protocol (IP) バージョン4のヘッダチェックサムは、1の補数の加算と1の補数を使用して計算されます。このチェックサムは、IPヘッダのエラーを検出するために使用されます。もしチェックサムが一致しなければ、パケットは破棄されます。
3.2. 2の補数の特徴
2進数 | 10進数 | 2の補数 | 2の補数の10進数 |
0000 | 0 | 0000 | 0 |
0001 | 1 | 1111 | -1 |
0010 | 2 | 1110 | -2 |
0011 | 3 | 1101 | -3 |
0100 | 4 | 1100 | -4 |
0101 | 5 | 1011 | -5 |
0110 | 6 | 1010 | -6 |
0111 | 7 | 1001 | -7 |
1000 | 8 | 1000 | -8 |
1001 | 9 | 0111 | 7 |
1010 | 10 | 0110 | 6 |
1011 | 11 | 0101 | 5 |
1100 | 12 | 0100 | 4 |
1101 | 13 | 0011 | 3 |
1110 | 14 | 0010 | 2 |
1111 | 15 | 0001 | 1 |
この表を見てわかるとおり、2の補数では、1の補数+1となっています。各ビットを反転させてから最下位ビットに1を加えています。そのため0は0000一つになり、加算や減算がシンプルになっています。
3.3. 2の補数が有効である理由
2の補数がコンピュータで広く使用されている主な理由は以下の通りです。
- 加減算の統一化:2の補数を用いることで、減算を加算として処理できます。これは、ハードウェア上で減算器を設計する必要がなく、加算器だけで済むため、回路設計が簡素化されます。
- 0の一意性:1の補数では「+0」と「-0」の2つの0が存在しますが、2の補数では0の表現が1つだけで済みます。これにより、計算処理がより効率的かつ正確になります。
- オーバーフローの検出:2の補数表現では、演算中に桁あふれ(オーバーフロー)が発生した場合、符号ビットの変化として検出しやすくなります。これにより、エラーの検出と処理が容易になります。
3.4. 2の補数の導出方法
この2段階の方法により2の補数は導出できます。