第二回-04 コンピュータ上の数値の表現 (2) 負の数を含む整数の2進数による表現〜2の補数表現

前ページでは、0 を含む正の整数を表現する 2 進数について学んだ。本ページでは、負の数を含む整数を表現する 2 進数について学ぶ。

ご存知の通り、10 進数で負の数を表現する場合、マイナス (−) 記号を用いる。
すなわち、10 進数では数字の 0 〜 9 を並べただけで負の数が表現されることはない。

一方、現在学んでいる 2 進数では 0 と 1 の数字を並べただけで負の数が表現されることがある。
なぜかというと、そのように 2 進数を構成した方が、コンピュータの黎明期にコンピュータを開発するときに都合が良かったからである。

2 進数で負の数を表現する方法は、歴史的に様々なものが試されてきた。
現在は「2の補数表現」という手法を用いるのが主流である。本ページではこの表現方法を学ぶ。

負の整数の表現〜2の補数表現〜

さて、0 と 1 を並べて作られる 2 進数で負の整数を表現する場合、以下の2つを考える必要がある。
  1. どの範囲の数値を表現させるか?
  2. 0 と 1 からなる並びにどのように数値を割り当てるか?
ひきつづき、4 ビットの 2 進数を例に考えよう。
まず「どの範囲の数値を表現するか?」から考える。0 を含む正の整数のみを表現したときの範囲は「0〜15の16通り」だった。

16 通りある 0 と 1 のパターンに負の整数も割り当てるのであるから、表現される正の整数の範囲は当然狭くなる。
2の補数表現では、16通りの半分を負の整数に割り当てることになっている。 すなわち、表現される範囲は、「-8 から 7」の 16 通りである。

細かく言えば、下記の通りである。 次に、これらの整数をどのように 2 進数のパターンに割り当てるかを考える必要がある。
0 を含む正の整数との共通部分である 0 〜 7 に対しては、前ページと同じパターンを割り当てるのがシンプルだろう。
すなわち、下図の通りである。



問題は、負の整数をどのように上図の空き領域に割り当てるかである。

結論を言えば、2の補数表現では、下図のように負の整数を割り当てる。



図に書かれているように、ポイントは下記の2点である。 2 の補数表現が一見不自然に見えるのは、本来連続しているはずの -1 と 0 が
2進数のパターン上では連続していない (1111 と 0000) ことではないだろうか。

これは、下図のように 4 ビットの加算を考えると、連続していると考えることもできる。
すなわち、-1 を表現する 1111 に 1 を足すと、桁上がりが発生して 10000 になるが、
4 ビットの範囲のみを考えると 桁上がりの 1 は捨てられて 0000 になり、これは 10 進数の 0 になるのである。
そのため、連続していないのは 0111 と 1000 の部分 (7 と -8 の部分) のみと言える。





0を含む正の整数のみの場合と負の整数を含む場合との比較

これで4 ビットの場合において、「0を含む正の整数のみを表現する 2 進数」と「負の数を含む整数を表現する 2 進数」を学ぶことができた。
比較のために 2 つを一つの表にまとめてみよう。以下の通りである。

ポイントは、表の上半分 (0000 〜 0111) の 2 進数は、「0を含む正の整数」と解釈しても「負の数を含む整数」と解釈しても同じ結果になることである。
一方、表の下半分 (1000 〜 1111) の 2 進数は、「0を含む正の整数」と解釈した場合と「負の数を含む整数」と解釈した場合とで結果が異なる。



この二つの領域は、2進数の左端の桁 (ビット) である MSB (Most Significant Bit) を見ることで区別できる。
MSB が 0 の場合、10進数の値は 0 を含む正の整数ひとつに確定する。
MSB が 1 の場合、10進数の値は正の整数の場合と負の整数の場合とで異なる。

さらに言えば、負の数を含む整数を表現する際、MSB が 1 であることは、その整数が負の数であることを意味するとも言える。
すなわち、負の数を含む整数を表現する場合においては MSB は負の数を表す符号である。


8 ビットの 2 進数でも確認

以上、4ビットの場合を例に、2の補数表現による負の整数の表現について学んできた。
以上で学んだことは 4 ビット以外のビット数の 2 進数でも成り立つ。

8 ビットの場合でも確認してみよう。
8ビットの2進数で0を含む正の整数を表現すると、下図のように 0 〜 255 の 256 通りの数値を表現できる。
それが、負の数を含む整数を表現すると、-128 〜 127 の 256 通りになる。

参考までに述べれば、 n ビットの2進数で0を含む正の整数を表現すると、0 〜 2n -1 の 2n 通りの数値を表現でき、
負の数を含む整数を表現する場合は -2n-1 〜 2n-1 - 1 の 2n 通りとなる。



上図を見ると、左端のビットである MSB の値が 1 のときのみ、正の整数と負の整数とで二通りの値をとり得ることがわかる。
これは 4 ビットで学んだことと同じである。

なお、2 進数のビット数が増えると、桁がどんどん大きな数となり、非常に見にくい数となる。
そのため前ページでも述べたように、「1111 1100」と 4 ビットごとに空白をいれたり、
「1111_1100」のように 4 ビットごとにアンダーバー ( _ ) を入れるなどして見やすくするための工夫をすることが多い。


負の整数を表す 2 進数をどのように 10 進数に変換するか?

さて、8 ビットの 2 進数の表を見たが、256 通りの数があるため、 表の全ての数を書き出すことは現実的ではないことがわかる。
4 ビットの 2 進数ならば、表を全て書き出すことで例えば「1101 を負の整数と解釈すると -3」とすぐわかる。
しかし、例えば 8 ビットの 2 進数において「1010 1101 を負の整数と解釈すると 10 進数でいくつか?」という問いにはどう答えれば良いだろうか?

ちなみに、「1010 1101 を0を含む正の整数と解釈すると 10 進数でいくつか?」という問いには定義より簡単に答えられる。
下記の計算より 173 である。

1010 1101 = 27 + 25 + 23 + 22 + 20
          = 128 + 32 + 8 + 4 + 1 = 173 

このような計算方法を、負の整数の場合でも知りたいところである。
ここでその方法の解説をし、本ページを終えることにしよう。

例として、先程に引続き 8 ビットの 2 進数 1010 1101 が負の整数である場合の値を求めることを目指す。

2進数が正の整数である場合の計算はできるのであるから、それを活かして計算する方針をとる。
流れだけを先に解説すれば、以下の手順で計算する。
  1. 負の整数である 2 進数の正負を逆転し、正の整数を表す 2 進数にする。言い替えれば、負の整数である 2 進数の絶対値に対応する 2進数を求める
  2. 正の整数化した 2 進数を定義に基づいて 10 進数の整数に変換する
  3. 求めた正の 10 進数の整数は、求めたい負の整数の絶対値なのであるから、−記号をつければ答えが得られる
この流れに沿って 8 ビットの 2 進数 1010 1101 に対応する負の数を計算してみよう。
  1. 負の整数である 2 進数の正負を逆転
    その方法は「2 進数の 0 と 1 を反転し、最後に 1 を足す」である。やってみよう。

    // 2 進数の 0 と 1 を反転
    1010 1101 → 0101 0010
    
    // 1 を足す
       0101 0010
    +)         1
    ------------
       0101 0011
    

    すなわち、元の負の整数の絶対値に対応する2進数は 0101 0011 であることがわかった。

  2. 正の整数化した 2 進数を正の 10 進数の整数に変換
    これは計算するだけである。

    0101 0011 = 26 + 24 + 21 + 20
              = 64 + 16 + 2 + 1 = 83
    

    よって、元の負の整数の絶対値は10 進数で 83。

  3. −記号をつける
    よって、 8 ビットの 2 進数 1010 1101 を負の整数と解釈すると -83
まとめると、8 ビットの 2 進数 1010 1101 を正の整数と解釈すると 173、負の整数と解釈すると -83 であることがわかった。

以上で、2 進数が与えられたとき、それを0を含む正の整数と解釈したときと負の整数と解釈したときの
10 進数の値を、表を書かなくとも求められるようになった。



←第二回-03 コンピュータ上の数値の表現 (1) 0 を含む正の整数の2進数による表現第二回-05 C/C++ で正負の整数を確認→

非情報系学生のための C/C++ 入門に戻る