さて、今日は文字コード入門の第2回です。

NS binary merger simulation 012
 前回はASCIIだったから、今回はJIS X 0201やJIS X 0208の話をするのか、あるいはいきなりUnicodeか? と思われるかもしれませんが、今回は、さらに一歩戻って、2進数、16進数の話をします。
 なんだよー! そんなのわかってるよー! という人も、頭の整理だと思ってお付き合いくださると幸いです。

0から15まで

まず10進数で0から15までいくつになるでしょうか。これはもう覚えるしかないと思いますので覚えてください。もっとも、丸暗記しなくても自然に覚えてきますよね。

10進数 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16進数 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
2進数 0b 1b 10b 11b 100b 101b 110b 111b 1000b 1001b 1010b 1011b 1100b 1101b 1110b 1111b

10進数と16進数の換算

まず、10進数と16進数の関係を見ましょう。

 10進数は、0から9まで10個の数字があります。だから、0番から9番まで、10人の選手の背番号を1桁で表すことが可能です。
 16進数は、0からFまで16個の数字があります。だから、0x0番から0xF番まで、16人の選手の背番号を1桁で表すことが可能です。

 10進数で9番の次の選手を考えると、もう数字がありませんから繰り上がりが起こり、10番になります。
 16進数で9番の次の選手を考えると、まだ数字があり、A番の選手になります。

 15までの10進数と、1桁の16進数の換算では、最悪10進数の10は16進数の0xAと、10進数の15は16進数の0xFという2つだけ覚えていればいいと思います。

 0xAは、16進数のAという意味の書き方で「ヘキサのエー」などと読みます。英語ではhexadecimal Aと読むようです。
 10進数の10を、他の進数と区別するために10(dec)と書くこともあります。本稿では特に但し書きがない数字は10進とします。

10進数と2進数の換算

2進数は、0と1と2個の数字しかありません。だから、1桁の背番号だと、0b番と1b番と2人の選手しか表せません。
 2進数は、区別のため1bのようにバイナリーのbという文字を付けることがあります。読み方は「バイナリーの1」です。

 10進数で1b番の次の選手を考えると、もう繰り上がりが起こって10b番になります。次が11b番です。

 2進数は、10進数で2 2にあたる数がいくつになるかを覚えるといいです。
 2 0は1で、1b。
 2 1は2で、10b。
 2 2は4で、100b。
 2 3は8で、1000b。
 2 4は16で、10000bです。
 こうすると、10進の9は2進のいくつか、というとき、8+1だから1000b+1bで1001b、という風に暗算できます。
 2の冪乗(べきじょう)は2 16まで覚えた方がいいと思います。
 特に2 8=256、210=1024、216=65536というのは特によく使います。

 2進数1桁のことを1ビットと言います。ビットはbinary digitという意味の英語です。
 よく「コンピューターはゼロとイチの世界…」などと言われますが、コンピューターの中で0bと1bはトランジスターの電子の状態や、ディスクの磁性体の状態、光ディスクの凸凹のような2値を保持するのに使います。

 2進数はよく、ある状態を表すのに何ビットの2進数が必要かを考えます。
 たとえば歩行者用信号は赤と青と2つの状態しかありませんので0bと1b、1ビットで足ります。

 自動車用信号は赤黄青の3つの状態がありますので0b、1b、10bと2ビットを消費します。11bは欠番になります。

 1桁の10進数0から9を2進数化すると、0bから1001bまで4ビットを消費します。1010b=10から1111b=15までの6個の番号が欠番になります。
 これは3ビットだと8までだから足りなくて、その倍の4ビットまでだと16までだからちょうど多すぎるので、4ビットだなーと考えます。

 AからZまでアルファベット大文字26文字を符号化するのに何ビット掛かるか。
 4ビットで16までだと足りない。その倍の5ビットだとちょうど多すぎるので、5ビットです。
 Aが0b、Bが1b…という風に符号化すると、Zは25=16+8+1=10000b+1000b+1b=11001bです。
 5ビットフルの11111bは100000b=32の1つ手前の31ですから、6個欠番が出来ます。
 最初期のテレックスのコード(ボドーコード)は5ビットだったそうです。
  Baudot Code - Wikipedia

16進数と2進数の換算

10進数は人間が日常生活に使います。コンピューターは内部で2進数で研究しています。ではそれ以外の16進数をなぜ覚えるのでしょうか。理由は2進数が桁数が多すぎる、でも10進数に暗算するのは面倒くさいからです。
 たとえばASCIIコードでABCは2進数で0100 0001 0100 0010 0100 0011bとなります。パッと見てもどこが切れ目か分かりません。
 これを16進数に直します。というのは、2進数の02進数4桁が16進数1桁にばっちりマッチするからです。
 上の0100 0001 0100 0010 0100 0011bの場合は4桁ずつ16進数にすると0x41 0x42 0x43で、なるほどASCIIコードのABCに該当します。

Perlでの換算

理論編はここまでにして(少ないわ!)Perlで上記の計算をどのようにするのか研究します。

10進数と16進数の換算

プログラムで0x00、0x10のように16進数の数字リテラルを書くことが出来ます。

#! /usr/local/bin/perl
#
# hexDec.pl -- 16進数から10進数に変換

use strict;
use warnings;
use 5.010;

for my $i (0x0 .. 0xF) {
 say $i;
}

 実行するとこうなります。

[sample]$ ./hexDec.pl
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

 10進数を16進数に直すにはsprintfを使います。

#! /usr/local/bin/perl
#
# decHex.pl -- 10進数から16進数に変換

use strict;
use warnings;
use 5.010;

for my $i (0 .. 15) {
 say "10進数の$iは16進数だと0x", sprintf("%x", $i), "です。";
}

 どうだ。

[sample]$ ./decHex.pl
10進数の0は16進数だと0x0です。
10進数の1は16進数だと0x1です。
10進数の2は16進数だと0x2です。
10進数の3は16進数だと0x3です。
10進数の4は16進数だと0x4です。
10進数の5は16進数だと0x5です。
10進数の6は16進数だと0x6です。
10進数の7は16進数だと0x7です。
10進数の8は16進数だと0x8です。
10進数の9は16進数だと0x9です。
10進数の10は16進数だと0xaです。
10進数の11は16進数だと0xbです。
10進数の12は16進数だと0xcです。
10進数の13は16進数だと0xdです。
10進数の14は16進数だと0xeです。
10進数の15は16進数だと0xfです。
[sample]$

 できたー!

10進数と2進数の換算


 2進数の数字リテラルは書けません。以下のようなコードはエラーになります。

#! /usr/local/bin/perl
#
# binDec.pl -- 2進数と10進数(ダメ)

use strict;
use warnings;
use 5.010;

for my $i (0b .. 1111b) { # ダメ
 say $i;
}

 ダメなりに一応怒られておきます。

[sample]$ ./binDec.pl
Bareword found where operator expected at ./binDec.pl line 9, near "1111b"
(Missing operator before b?)
syntax error at ./hexDec3.pl line 9, near "1111b"
Execution of ./hexDec3.pl aborted due to compilation errors.

 裸のワード「1111b」が怒られてますね。

 sprintfで10進数から2進数はできます。

#! /usr/local/bin/perl
#
# decBin.pl -- 10進数と2進数

use strict;
use warnings;
use 5.010;

for my $i (0 .. 15) {
 say "10進数の$iは2進数だと", sprintf("%b", $i), "bです。";
}

 どうでしょう。

[sample]$ ./decBin.pl
10進数の0は2進数だと0bです。
10進数の1は2進数だと1bです。
10進数の2は2進数だと10bです。
10進数の3は2進数だと11bです。
10進数の4は2進数だと100bです。
10進数の5は2進数だと101bです。
10進数の6は2進数だと110bです。
10進数の7は2進数だと111bです。
10進数の8は2進数だと1000bです。
10進数の9は2進数だと1001bです。
10進数の10は2進数だと1010bです。
10進数の11は2進数だと1011bです。
10進数の12は2進数だと1100bです。
10進数の13は2進数だと1101bです。
10進数の14は2進数だと1110bです。
10進数の15は2進数だと1111bです。
[sample]$

8進数に注意!

コンピューターの世界では8進数(octal)も使いがちです。Perlでは先頭に0をつけるとオクタルになります。
 010は10進数の8になります。
 これを知らないで、数字の桁数を合わせようと思って10進数のつもりの数字の先頭に余計なゼロをつけると変になります。
#! /usr/local/bin/perl
#
# octDec.pl -- 8進数と10進数

use strict;
use warnings;
use 5.010;

say "001 = ", 001;
say "010 = ", 010;
say "100 = ", 100;

だとこうなります。

[sample]$ ./octDec.pl
001 = 1
010 = 8
100 = 100
[sample]$

 1は10進も8進も1ですから大丈夫、100はゼロで始まらないから100でいいんですが、010は8進で解釈されて、10進では8と表示されてしまいます。
 では、0始まりの数字列に8とか9とか書いたらどうなるでしょうか。

#! /usr/local/bin/perl
#
# octDec2.pl -- 8進数と10進数その2

use strict;
use warnings;
use 5.010;

say "008 = ", 008;
say "090 = ", 090;

 エラーになります。

[sample]$ ./octDec2.pl
Illegal octal digit '8' at ./octDec2.pl line 9, at end of line
Illegal octal digit '9' at ./octDec2.pl line 10, at end of line
Execution of ./octDec2.pl aborted due to compilation errors.
[sample]$

 8進数としては不当な桁8および9がある、と怒られますね。
 でも、怒られて気づくだけまだましで、10と書くつもりで010とか書いてしれっと8と解釈されて間違った結果が出るほうが恐ろしいですね。
 注意しましょう。