情報の表現

整数の表現

1.非負の整数

コンピュータ内部の表現では,非負の整数は通常の2進数で表現される。また,使用するビット長は,8ビット,32ビットなどと固定される。
例えば 25(10) という値は,8ビットで表現する場合 00011001(2) となる。よって,

8ビット使用して表現できる整数は,00000000(2) ~ 11111111(2) ,つまり 0 ~ 28 -1

である。同様に

16ビット使用して表現できる整数は,0 ~ 216 -1
32ビット使用して表現できる整数は,0 ~ 232 -1

である。

2.負の整数

2.1 2の補数

コンピュータ内部では,2つの状態 0 と 1 しか使えないので,我々が通常使用する - (マイナス)記号を使うことはできない。つまり,負の数も 0, 1 を使って表現するしかない。

多くの場合,負の数の表現には2の補数を使用する。2の補数とは,正の整数 n に対して,以下のように -n を定義するものである。ここで,数値を表現するビット数は,16や32のように固定して考える。

2の補数の作り方
  1. 正の整数 n を2進数で表す。ただし最上位のビットは 0 とする。
  2. 各ビットを反転する。(1→0,0→1)
  3. それに1を加える
例1
整数は 8 ビットで表現するものとする。
n = 18(10) とする。(8ビットの場合だと,最初のビットが 0 となる値の範囲は 1(2) ≦ n ≦01111111(2) ,つまり 1 ≦ n ≦ 127(=27-1))
n = 00010010(2)
各ビットを反転して,11101101
これに 1 を加えて,11101110
これが,-18(10) の内部表現である。

n = 0 についても同様の変形をしてみる。
各ビットを反転して,11111111
これに 1 を加えて,100000000
8ビットであるので,最上位のビット1は保持されない。従って結果は,00000000 となり,0 = -0 が成り立つ。

以上から,次のような関係ができる。

元の数
(10進数)
元の数
(2進数) 
2の補数
(負の数) 
0 00000000 00000000 
1 00000001 11111111 
2 00000010 11111110
3 00000011 11111101
4 00000100 11111100
 

: 
126 01111110 10000010
127 01111111 10000001
128 10000000 10000000

この表の最下段の 10000000 は元の数と2の補数が同じ表現になっているので,+128 か -128 かどちらかに定めないといけない。負の数の最上位のビットはすべて 1 であるから,負の数とした方が都合がよく,-128 と定める。

10000000(2) = -27 = -128

同様に

16ビット : 1000000000000000(2) = -215 = -32768
32ビット : 1000000000000000000000(2) = -231

と定義する。

この定義から,正の数は最上位のビットが 0,負の数は最上位のビットが 1 となる。

2.2 符号付の整数で表現できる範囲

以上のことから,負の数に 2 の補数を使うとき,8ビットの符号付きの整数では -128 ~ 127 の範囲の値が使用できる。

同様に,16 ビットの符号付きの整数では - 215 ~ 215 -1 の範囲の値が,32 ビットの符号付きの整数では - 231 ~ 231 -1 の範囲の値が使用できる。

いずれも負の数の個数が 1 つ多くなる。

2.3 負の数に2の補数を使用する理由

-1は?

負の数に 2 の補数を使う理由は,コンピュータ内部では有効なビット数が固定されていることで,負の数の加算に特別な仕組みを用意しなくても済むことである。

例えば

0000 0001 + 1111 1111 = 1 0000 0000 (*)

となるが,有効ビット数が 8 の場合,右辺の9桁目のビットつまり左端のビットは保持されない。よって 1111 1111 と 0000 0001 の和は 0000 0000,つまり 0 となる。このことから,0000 0001 の負の数として 1111 1111 を採用すれば,負の数を含む和の計算が(従って差の計算も)正の数の和の計算だけでできるのである。

一般に

以下,2の補数が負の数として使われる理由を,一般的な場合に考えてみる。

ある正の数 A に対して

A + B = 1 0000 0000 (**)

となる数 B を考える。-1 の場合のように最上位のビットは消えて無くなるので,式(**)は

A + B = 0

という式と同じである。つまり,B が A の負の数の定義を満たしていることが分る。

次に,この B をどのように作成すれば良いかを考える。上の式(*)から,

1 0000 0000 - 0000 0001= 1111 1111

である。よって(**)から

A + (B - 1) = (A + B) - 1 = 1 0000 0000 - 1 = 1111 1111

である。この式から,B-1 は A の各ビットを反転したものであることがわかる。よって B は, A の各ビットを反転したものに 1 を加えたものになる。

例2
例1のように,使用するビット数は8ビットとし,n = 18 とする。例1の計算から,
n =00010010
-n =11101110
である。これらを加えると
00010010 + 11101110 = 100000000
従って,9ビット目を捨てた8ビットの表現では,和が 0 となることが分かる。

負の数が入った値の計算

2の補数を使うと,正の数と負の数の和(つまり引き算)や負の数度同士の和も,正の2進数の整数の和で計算できる。

例3
21 から 18 を引く計算は 21 と -18 の和を計算する。
21(10) = 00010101(2)
-18(10) = 11101110(2)
21(10) - 18(10) = 00010101(2) + 11101110(2) = 100000011(2) = 00000011(2) = 3(10)
最後から2つ目の等号は,有効桁数を越えた 9 ビット目を消去している。
例4
18 から 21 を引く計算は 18 と -21 の和を計算する。
18(10) = 00010010(2)
-21(10) = 11101011(2)
18(10) - 21(10) = 00010010(2) + 11101011(2) = 11111101(2)
一方 3 の補数は,上の表より,11111101(2)
よって,18 - 21 = -3 が成り立つ。

これらの計算結果から,一般に引き算も2進数の和で計算できることが分る。 つまり加減共に同一の回路で計算できることになり,

回路が単純化でき処理が速くなる

という利点が生まれる。そのため,2の補数を負の表現として採用しているシステムが多い。

演習

  1. 8ビットの値 10000000 の2の補数が 10000000 であることを確認せよ。
  2. 負の数はすべて2の補数で表現するとする。
    99(10)の負の表現を求めよ。
    次に,求めた値と-18(10)の和を2進数の和として計算し,それが-117(10)と一致することを確かめよ。
    数値はすべて8ビットで表現されるものとする。

3.オーバーフロー(overflow)

数値演算や入力などの結果、扱える数値の最大値を超えることをオーバーフローという。プログラミングなどでは,オーバーフローをチェックせず,計算したままの結果を返すことがある。例えば 8 ビットの符号付の整数の場合,127 + 1 はオーバーフローとなる。よってその事を示唆するメッセージが表示されるのを期待してしまう。しかし実際にはエラーメッセージは表示されずに,-128 が表示されることがある。上の式の計算結果は

0111111 + 00000001 = 10000000

となり,右辺は -128 の2の補数表現なので,-128 という値を返すのである。