No221 16進数のナゾ

コンピュータに関する話でしょっちゅう出てくるコトバの一つに
16進数というものがあります。

コンピュータが2進数で動いている、という話はどこかで聞いたと
いう方も多いでしょう。ですがなんで16進数なのでしょうか?

そもそも16という数字がワケわかりません。

2進数ならともかく、なんで16進数なんていう中途半端な進法が
使われるのでしょうか?

今回はこのナゾに迫ります。


1. 16という値の意味

ネタを先に明かしておきます。
16進数というのは2進数の表記方法を改善しただけのもので、それ
以上の深い意味はありません。

2の4乗(=2進数で4ケタ分=4ビット)は16です。
つまり、2進数の4ケタ分を1ケタで表記できる方式なのです。

だったら、10進数でも良さそうなものですが、2進数→10進数は
非常に面倒です。
ですが、2進数←→16進数の変換は相互に簡単なルールで行えます
から便利で良かったのです。

要は2進数での表記をラクにした方式が16進数表記というワケです。

言ってみれば、今回の解説はこれが全てなのですが、2進数自体が
イマイチわからないという方も多いでしょうから、そこからいき
ましょう。


2. 2進数

10進数が10種類の数字(0~9)を使って計算をします。
それに対し、2進数は2種類の数字(0と1)を使って計算をします。

10進数では10種類の文字が使えますから、0→1→2→3...→9まで
1ケタの数字で表現でき、9の次にケタ上がりが起きて、10となり
ます。
ですが、2進数では2つの数字しかありませんから、0→1 しかあり
ません。その次の値(10進数の2)はケタ上がりが起きて 10 と
なります。

表形式にしてみましょう。

10進数 2進数
 0 … 0
 1 … 1
 2 … 10
 3 … 11
 4 … 100
 5 … 101
 6 … 110
 7 … 111
 8 … 1000
 9 … 1001
10 … 1010

なんとも妙な感じですが、2種類しか数字がないため、めった
やたらとケタ数が増えていきます。

例えば、
 1,000 … 1111101000 (10ケタ)
 10,000 … 10011100010000 (14ケタ)
  100,000 … 11000011010100000 (17ケタ)
 1,000,000 … 11110100001001000000 (20ケタ)

と、すごいペースでケタ数が増えていきます。

このようにやたらとケタ数が増えると書くのも読むのも大変です。

これを少しでもラクに扱えるようにと工夫したのが16進数なの
です。


3. 16進数

さて、問題の16進数です。

上述の通り、10進数は10種類の数字(0~9)、2進数は2種類の
数字(0と1)を使います。

では16進数は?

そりゃ、16種類の数字を使います。だから0~....?ってあれ?
数字は16種類もないですよ。
現代人は10進数しか使いませんから、数字は10種類に決まって
ます。
でも16進数を表記するには、何とかして16種類の文字を捻り出す
必要があります。

どうすれば良いのでしょうか?

そこで無理矢理考案されたのが、文字をアルファベットで代用
する方式でした。0~9の10種類に加えて、A~Fの6種類の文字を
「数字」として使うわけです。

ですので、16進数と10進数の対応は次のようになります。

10進数 16進数
 0 … 0
 1 … 1
 2 … 2
 3 … 3
 4 … 4
 5 … 5
 6 … 6
 7 … 7
 8 … 8
 9 … 9
10 … A
11 … B
12 … C
13 … D
14 … E
15 … F
16 … 10

これもまた2進数と違う意味で不思議な表記です。10になっても
ケタが変わらないというのは妙な感覚です。

16進数では2進数と逆に10進数よりも表記のケタ数が少なくなり
ます。

例えば、5ケタの10進数の40,000を16進数で表記すると9C40と
4ケタで済んでしまいます。

ここで「ははぁ」と思い当たる方もおられるかもしれません。

例えば、Windows上でアプリが異常終了した時のエラーコード、
MACアドレス(ネットワークで使われる機器のIDのようなもの)、
電子証明書の指紋(フィンガープリント)などはいずれも16進数
で表記されています。


4. 2進数←→16進数変換

最初に書いた通り、2進数と16進数は非常に簡単に相互変換ができ
ます。


10進数 16進数 2進数
 0 … 0 … 0
 1 … 1 … 1
 2 … 2 … 10
 3 … 3 … 11
 4 … 4 … 100
 5 … 5 … 101
 6 … 6 … 110
 7 … 7 … 111
 8 … 8 … 1000
 9 … 9 … 1001
10 … A … 1010
11 … B … 1011
12 … C … 1100
13 … D … 1101
14 … E … 1110
15 … F … 1111
16 … 10 … 10000

注目していただきたいのは、最後の16のところです。
2進数と16進数が同時にケタ上がりしています。つまり、2進数の
4ケタ毎に16進数もケタ上がりするということです。

これは、2進数4ケタをそのまま16進数に置き換えられることを
示しています。

例えば、16ケタの2進数 を16進数に置換してみましょう。
(以下では見やすいように2進数の4ケタ毎に空白を入れています)

例1: 1010 1100 0101 0011

 1010 1100 0101 0011
  ↓ ↓ ↓ ↓
 1010 1100 101 11
  ↓ ↓ ↓ ↓
  A C 5 3
 
 →16進数では、AC53となります。

例2: 1110 1100 1101 0011 (2箇所の0と1を変更)

 1110 1100 1101 0011
  ↓ ↓ ↓ ↓
 1010 1100 1101 11
  ↓ ↓ ↓ ↓
  E C D 3

 →16進数では、ECD3となります。

この通り非常に単純な置換が可能です。
もちろん、16進数から2進数への変換も同様の手順で行えます。

ですが、10進数←→2進数の変換はこうはいきません。
1ケタづつ計算をするしかないのです。
つまり、こうなります。

例1: 1010 1100 0101 0011
 これを10進数に直すには、次のような計算が必要になります。

 1 * 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 0 * 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 1 * 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 0 * 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 1 * 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 1 * 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 0 * 2* 2* 2* 2* 2* 2* 2* 2* 2 +
 0 * 2* 2* 2* 2* 2* 2* 2* 2 +
 0 * 2* 2* 2* 2* 2* 2* 2 +
 1 * 2* 2* 2* 2* 2* 2 +
 0 * 2* 2* 2* 2* 2 +
 1 * 2* 2* 2* 2 +
 0 * 2* 2* 2 +
 0 * 2* 2 +
 1 * 2 +
 1
 = 44115

 ものすごく複雑に見えますが、要は2進数の各ケタに2のn乗をかけた
 計算を繰り返しているだけです。
 各行の最初の1文字が変換元の2進数の値の1ケタにあたります。
 (結果的に2進数を縦書きした形になっています)

 16進数に比べて、明らかに面倒な計算が必要になることがわかる
 と思います。

 実は2進数→10進数はまだ楽で、10進数→2進数変換ははるかに面倒
 な計算が必要となります。

 基本的には、2進数の全てのケタ(この例では16ケタ)が1か0かを
 判断し、必要な計算をするという手順を繰り返すことになります。

 ※以下の計算式は「求めるのが大変」なのを示すために書いたもの
  ですので、読み飛ばしていただいて問題ありません。

 1) 44115 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 か?
  を調べます。
  この 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 というのは、
  2進数では 1000 0000 0000 0000、10進数では 32768 となります。
  なので、44115 ≧ 32768 かどうかを調べることになります。
  結果はYesですから、
  変換結果に 1000 0000 0000 0000 を加え、44115-32768=11347 を得て、
  以降はその結果の11347を使います。

 2) 11347 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 か?
  を調べます。
  今度は、2進数では 100 0000 0000 0000、10進数では 16384 です。
  なので、11347 ≧ 16384 かどうかを調べることになります。
  結果はNoですから、
  そのケタ位置は2進数では0であることがわかります。
  値がゼロですので、特に計算は行いません。

 3) 11347 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 りも大きいか?
  を調べます。
  今度は、2進数では 10 0000 0000 0000、10進数では 8192 です。
  なので、11347 ≧ 8192 かどうかを調べることになります。
  結果はYesですから、
  変換結果に 10 0000 0000 0000 を加え、1010 0000 0000 0000 とします。
  また、11347-8192=3155 を得、以降はその結果の3155を使います。

 4) 3155 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 か?
  を調べます。
  今度は、2進数では 1 0000 0000 0000、10進数では 4096 です。
  なので、3155 ≧ 4096 かどうかを調べることになります。
  結果はNoですから、
  そのケタ位置は2進数では0であることがわかります。
  値がゼロですので、特に計算は行いません。

 5) 3155 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 か?
  を調べます。
  今度は、2進数では 1000 0000 0000、10進数では 2048 です。
  なので、3155 ≧ 2048 かどうかを調べることになります。
  結果はYesですから、
  変換結果に 1000 0000 0000 を加え、1010 1000 0000 0000 とします。
  3155-2048=1107 を得、以降はその結果の1107を使います。

 6) 1107 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2* 2 か?を
  調べます。
  今度は、2進数では 100 0000 0000、10進数では 1024 です。
  なので、1107 ≧ 1024 かどうかを調べることになります。
  結果はYesですから、
  変換結果に 100 0000 0000 を加え、1010 1100 0000 0000 とします。
  1107-1024=83 を得、以降はその結果の83を使います。

 7) 83 ≧ 2* 2* 2* 2* 2* 2* 2* 2* 2 か?を調べ
  ます。
  今度は、2進数では 10 0000 0000、10進数では 512 です。
  なので、83 ≧ 512 かどうかを調べることになります。
  結果はNoですから、
  そのケタ位置は2進数では0であることがわかります。
  値がゼロですので、特に計算は行いません。

 8) 83 ≧ 2* 2* 2* 2* 2* 2* 2* 2 か?を調べます。
  今度は、2進数では 1 0000 0000、10進数では 256 です。
  なので、83 ≧ 256 かどうかを調べることになります。
  結果はNoですから、上と同様で計算は不要です。

 9) 83 ≧ 2* 2* 2* 2* 2* 2* 2 か?を調べます。
  今度は、2進数では 1000 0000、10進数では 128 です。
  なので、83 ≧ 128 かどうかを調べることになります。
  結果はNoですから、上と同様で計算は不要です。

 10) 83 ≧ 2* 2* 2* 2* 2* 2 か?を調べます。
  今度は、2進数では 100 0000、10進数では 64 です。
  なので、83 ≧ 64 かどうかを調べることになります。
  結果はYesですから、
  変換結果に 100 0000 を加え、1010 1100 0100 0000 とします。
  83-64=19 を得、以降はその結果の19を使います。

 11) 19 ≧ 2* 2* 2* 2* 2 か?を調べます。
  今度は、2進数では 10 0000、10進数では 32 です。
  なので、19 ≧ 32 かどうかを調べることになります。
  結果はNoですから、計算は行いません。

 12) 19 ≧ 2* 2* 2* 2 か?を調べます。
  今度は、2進数では 1 0000、10進数では 16 です。
  なので、19 ≧ 16 かどうかを調べることになります。
  結果はYesですから、
  変換結果に 1 0000 を加え、1010 1100 0101 0000 とします。
  19-16=3 を得ます。

 13) 3 ≧ 2* 2* 2 か?を調べます。
  今度は、2進数では 1000、10進数では 8 です。
  なので、3 ≧ 8 かどうかを調べることになります。
  結果はNoですから、計算は行いません。

 14) 3 ≧ 2* 2 か?を調べます。
  今度は、2進数では 100、10進数では 4 です。
  なので、3 ≧ 4 かどうかを調べることになります。
  結果はNoですから、計算は行いません。

 15) 3 ≧ 2 か?を調べます。
  結果はYesですから、
  変換結果に 10 を加え、1010 1100 0101 0010 とします。
  3-2=1 を得ます。

 16) 1 ≧ 1 か?
  なので2進数に 1 を加算。
  変換結果に 1 を加え、1010 1100 0101 0011 とします。
  1-1=0 となります。

 これだけ手間をかけてやっと目的の 1010 1100 0101 0011 という
 2進数を得ることができます。

 こんなのはとてもやってられません。
 だから、10進数で2進数の代用するというのは現実的でないのが
 わかります。


5. 余談:8進数が使われた時代も...

この16進数というのは何も絶対的な基準などではなく、単に便利だ
から使っているに過ぎません。

実際、かなり昔の話となりますが、1970年頃は16進数はほとんど
使われておらず、8進数がよく使われていたようです。(筆者も実際
に8進数を使われていた時代は全く知らず、古い資料で得た知識です)

8進数も16進数と目的は同じで、2進数表記の読みづらさを改善する
ことが目的でした。

8進数が愛用されたのは、当時のCPUは12ビットや24ビットのものが
多く、最少の情報単位が6ビットとなっているものが多かったため
です。
8進数は2進数3ケタ分(=3ビット)を1ケタで表記できますので、
6ビットの情報を表記するには丁度組具合が良く、2進数4ケタ分を
1ケタで表記する16進数よりも使い易かったのでしょう。

実際、1970年代に開発されたUNIXというOSには ファイル内容を
8進数で表示してくれる od (Octal dump:8進数出力)という
コマンドがありました。現在も使えるのですが、主として16進数
変換に利用されています。
今となっては、odコマンドの語源を知らない人も多いことでしょう。

こういった点でも時代の流れを感じられるのは面白い話です。


6. まとめ

16進数という表記がコンピュータ関連では多用されています。

コンピュータは2進数で動作しているのですが、2進数をそのまま
書くと非常に長くなってしまいます。

それを簡便に扱えるようにするため、2進数4ケタを1ケタで表記
できる16進数が多用されるようになっています。

実際、16進数と2進数の相互変換は計算なしででき非常に簡単です。

一方、10進数と2進数の相互変換は計算が必要となり、かなり面倒
で、簡単とは言えません。

もっとも、16進数が利用され始めたのはせいぜい1970年代後半の
話で、それ以前は8進数が多用されていたようです。
(当時は2進数をそのまま使っているケースも多かったようです)

今回はお盆明けなので、軽目の話題を短かい目に、と思ったのです
が、メルマガ史上、最長(本文が400行越え)になってしまいました。

「わかった!」と思っていただければ、とても嬉しいです。

次回もお楽しみに。


この記事が気に入ったらサポートをしてみませんか?