前号: No 220 / 次号: No 222 / 一覧に戻る

メールマガジン「がんばりすぎないセキュリティ」No221 (21/08/16)

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

前号: No 220 / 次号: No 222 / 一覧に戻る