こんにちは、ダックです。
研修にて、先輩の講義中にこんな説明がありました。
「コンピュータでの数を表現するときは 0 と 1 しか取れないので 2 進数で表します。しかし、マイナスがつく場合はまた違って、2 の補数を使います。」
普通に聞けばなんてことない説明です。
しかし 「ビット =2 進数」 だけで分かったつもりでいた私にはちょっとした衝撃が走りました。
ということで、ビットでの数の表し方について考えてみました。
正の数の表し方
まずは、最も基本的な正の数だけ、つまり 「符号無し」 の数を表す場合について見てみます。
正の数では、単純に 2 進数に変換するだけです。例えば 8 ビットで表す数があるとしましょう。 2 の 8 乗なので 256 通りの数が表せます。
10進数 |
2進数 |
10進数 |
2進数 |
0 |
0000 0000 |
100 |
0110 0100 |
1 |
0000 0001 |
・・・ |
・・・ |
2 |
0000 0010 |
127 |
0111 1111 |
3 |
0000 0011 |
128 |
1000 0000 |
・・・ |
・・・ |
129 |
1000 0001 |
10 |
0000 1010 |
・・・ |
・・・ |
・・・ |
・・・ |
255 |
1111 1111 |
負の数の表し方 ( 2 の補数)
では負の数はどうやって表すのでしょうか。負の数を含む数つまり 「符号付き」 の数を表すときには主に 2 の補数を使います。
2 の補数とは、正の数を全ビット反転させ、その値に 1 を足したものとして表現します。例として、8 ビットでの -7 はどのように表すことができるのかを示します。
表にすると以下のようになります。
符号付きの 8 ビットの数値で表すことができるのは、 -128 ~ 127 の 256 通りの数です。表すことができる数は同じですが、表すことができる値の幅が異なります。
10進数 |
2進数 |
10進数 |
2進数 |
-128 |
1000 0000 |
0 |
0000 0000 |
-127 |
1000 0001 |
1 |
0000 000 |
・・・ |
・・・ |
2 |
0000 0010 |
-100 |
1001 1100 |
3 |
0000 0011 |
・・・ |
・・・ |
・・・ |
・・・ |
-3 |
1111 1101 |
100 |
01100100 |
-2 |
1111 1110 |
・・・ |
・・・ |
-1 |
1111 1111 |
127 |
0111 1111 |
基本的に負の数は最上位ビットが 1 になります。 0 から始まるものは正の数を表します。 2 の補数を用いて符号付きの数を表す場合、正の数は符号無しの時と同じように表されます。
この 2 の補数最大の利点が演算のしやすさです。同じく 8 ビットでの -1+1 を考えてみましょう。
1111 1111 + 0000 0001 = 0000 0000
繰り上がりますが 9 ビット目は使えないので演算結果は 0000 0000 になります。このように負の数でも同じように演算できます。
負の数の表し方 (オフセットバイナリ)
符号付きには他の表し方もあります。 2 の補数に比べ使用されることは少ないですがオフセットバイナリ方式というものがあります。これは、あらかじめ決めた値(バイアス値)を引いておく方式です。この方式を使い、 8 ビットのバイアス値 128 の場合、以下の表のようになります。
10進数 |
2進数 |
10進数 |
2進数 |
-128 | 0000 0000 | 0 | 1000 0000 |
-127 | 0000 0001 | 1 | 1000 0001 |
・・・ | ・・・ | 2 | 1000 0010 |
-2 | 0111 1111 | ・・・ | ・・・ |
-1 | 1111 1111 | 127 | 1111 1111 |
単純な演算はこのままではできませんが、数の大小は分かりやすい表現になっています。
そして小数点へ
研修には続きがあります。
2 の補数を理解して、これでビットの表し方もばっちりかなと思った矢先のこと先輩講師はこう続けました。
「負の数はまあこんな感じで簡単なんだけど、もっと難しい浮動小数点というのがあります。 FPGA を使うなら知っておかないといけないね。」
ビットの世界の奥が深さに気づかされました。なかなか極めるのは大変そうです。