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行越え)になってしまいました。
「わかった!」と思っていただければ、とても嬉しいです。
次回もお楽しみに。