Rubyでのプログラミングではあまり計算機の中の都合を意識しなくてよい ようになっている。しかし、凝ったプログラムを作ろうとしたり、 Ruby以外で少し複雑な計算などを行なわせようとするとき、あるいは とくにコンピュータグラフィックスなどの基礎知識を習得したい場合には、 計算機の内部構造、とくに2進数の性質を知らないとスムーズに 理解できないことがある。しっかりと覚えておきたい。
計算機の内部では、数値も文字も画像も全て 1 と 0 の2進数 の状態で保存している。 人間にとって分かりやすい10進数でなく2進数が使われるのは、 計算機が何かを記憶するための格納場所であるメモリに 書き込むためには電気的にONかOFF (あるいは磁気的 にNかS)かの形で書くことになるからである。これを何個も組み合わせて一つのデー タ格納領域とする。たとえば、ONとOFFの箱を8個用意して、次のようなデータを 入れる。
OFF | ON | OFF | OFF | OFF | OFF | OFF | ON |
これは模式的な絵であるが、計算機のメモリの中では、 電気がONになっていたり、磁石がN極を向いている状態を想像するのが実状に近い。 このOFFとONの状態を2進数にしよう。
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
2進数の
128倍 | 64倍 | 32倍 | 16倍 | 8倍 | 4倍 | 2倍 | 1倍 |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
これは、64×1 + 1×1 = 65 となる。
いくら計算機が内部で2進数を使うとはいえ、2進数のまま数値を書いたので は長くて読みづらい。かといって、10進数に直すのは計算が面倒である。そのた め、2進数4桁をまとめて16進数にして数値を表記することが多い。
たとえば、10進数でもまとめて表記することがある。長さの尺度が「メート ル」のまま距離を表現したら大変なので、10進数3桁(10の3乗=1000)ごとにまと めて「キロ」メートルで表現することがある。逆に、10の-3乗メートルを「ミリ」 として表記したりする。また、金額を表記するときも3桁毎にまとめて 2,500,000円 のように10の3乗ごとにまとめてあたかも1000進法のようにして表 すことがある。このように何桁かをまとめて単位を付けたりすることは日常的に も身近なことである。
2進数4桁をまとめると、2**4=16個の数を表すことができる。
2進数 | 16進数 | 10進数 |
---|---|---|
0000 | 0 | 0 |
0001 | 1 | 1 |
0010 | 2 | 2 |
0011 | 3 | 3 |
0100 | 4 | 4 |
0101 | 5 | 5 |
0110 | 6 | 6 |
0111 | 7 | 7 |
1000 | 8 | 8 |
1001 | 9 | 9 |
1010 | a | 10 |
1011 | b | 11 |
1100 | c | 12 |
1101 | d | 13 |
1110 | e | 14 |
1111 | f | 15 |
ONとOFFの箱で出てきた、
OFF | ON | OFF | OFF | OFF | OFF | OFF | ON |
つまり
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
は、2進数で 01000001 だが、これを16進数で表すと4桁毎に変換すればよいので
0100
→ 4
0001
→ 1
となる。2進数 01000001
は、16進数で41
である。
ちなみに41は文字コードでいえば、アルファベッ
ト大文字Aに該当する。つまり、Aという文字を計算機の内部に記憶させたいとき
は
0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
のようにデータが格納されることになる。
16進数を10進数に変換するには、各桁に16の倍数を掛けたものを足す。 たとえば、16進数 56ce を10進数に直してみよう。
4096倍 (16**3) | 256倍 (16**2) | 16倍 | 1倍 |
5 | 6 | c | e |
cの桁は10進数で12を意味することと、eの桁は10進数で14を意味 することに注意して計算すると、
4096*5 + 256*6 + 16*12 + 14 = 22222
となる。
10進数を16進数に変換するには、
の2とおりの方法がある。
元の10進数を割れなくなるまで16で割り、 割ったときの余りを逆に拾って行けばよい。たとえば、10進数64206を16進数に 直してみよう。
16) 64206 (余り) 16) 4012 …… 14 → e 16) 250 …… 12 → c 16) 15 …… 10 → a 16) 0 …… 15 → f ↑下から上に読む
割り算の余りを下から順に読んだ、0xface が16進の値となる。
元の10進数を2進数に変換する。
2) 64206 (余り) 2) 32103 …… 0 2) 16051 …… 1 2) 8025 …… 1 2) 4012 …… 1 2) 2006 …… 0 2) 1003 …… 0 2) 501 …… 1 2) 250 …… 1 2) 125 …… 0 2) 62 …… 1 2) 31 …… 0 2) 15 …… 1 2) 7 …… 1 2) 3 …… 1 2) 1 …… 1 2) 0 …… 1 ↑ 下から上に読む
余りを下から上に読むと、
1111101011001110
となるが、これを1の位(右側)から4桁毎に区切る。
← 右から4桁毎に区切る 1111,1010,1100,1110
区切った2進数を16進数に直していく。
1111,1010,1100,1110 ↑ ↑ ↑ ↑ f a c e (16進数)
Rubyプログラムでは、プログラム中に書く数値の先頭に付ける記号(接頭辞)で 何進法かを指示できる。
接頭辞 | 意味 |
---|---|
なし | 10進数 |
0b | 2進数 |
0 | 8進数 |
0x | 16進数 |
0b1010
は、2進数の1010
(10進数でいえば10を)表すことになり、0x10f0
は、16進数の
10F0 (10進数でいえば4336)を表すことになる。
プログラム中に、0b1010
と書こうが 10
と書こ
うが、0xa
と書こうが、一度読み込まれれば計算機の内部ではど
れも10進数でいうところの10として扱われ、どれも全く同じである。これを出力
するときに何進法にするかは printf
の%つきフォーマットで選
択することができる。
以下に、printf
の%フォーマットで
数値を何進法で出すかの意味を示す。
%フォーマット | 何進法で出力されるか |
---|---|
%b | 2進法 |
%o | 8進法 |
%d | 10進法 |
%x | 16進法 |
これを利用すると、16進数を10進数に直したり、その逆をしたり することをRubyプログラムに任せることができる。
printf("16進の%xは10進で%dです\n", 0x555, 0x555) ↓ 16進の555は10進で1365です
printf("10進の%dは2進で%bです\n", 2002, 2002) ↓ 10進の2002は2進で11111010010です