第45章 2進数と16進数

 コンピューターは0と1で情報を扱うと前に話しました。これを意識してプログラムを扱うときには、10進法では少し考えにくくなってしまいます。この章ではそんなときに便利な概念について話します。


 では、今回の要点です。


 では、いってみましょう。


 さて、私たちは普段の生活で何の疑問もなしに10進数を使っています。(疑問を持って使っている人は、なかなか数学の素質があるかもしれませんね。)10進数とは、0〜9の10個の数字を使って表現された数のことです。数が無くなってしまう「9」の次は、桁をあげて「10」と表現するのですね。

 しかし、同じような理屈を使えば、0〜2でも、0〜6でも数値を表現することができます。新しい数字を作れば、20進数でも100進数でも表現することができます。

 そして、たとえ3進数で表現されていても、7進数で表現されていても、100進数で表現されていても、違う形であれ同じ数値を表現することが出来ます。(小数では循環小数になってしまうこともありますが。)そして、全ての表現は全く等価なのです


 では、先ずは考えやすい所から、0〜4の5個の数字を使った、5進数を考えてみましょう。

 先ず、上の10進数の定義に、5進数用の条件を当てはめてみましょう。すると、「5進数とは、0〜45個の数字を使って表現された数のことです。数が無くなってしまう「4」の次は、桁をあげて「10」と表現します。」となることが分かります。これが5進数です。

 では、実際に数を表現してみましょう。0の次は1です。1の次は2です。え? 当たり前だって? まぁ、我慢して下さい。

 では、4の次はいくらになるのでしょうか? そうですね。10です。10の次は11で、11の次は12です。

 そして、今度は14の次はいくらになるのでしょうか? そうですね。20です。では、44の次は? これは100になりますね。

 何だかとても当たり前のことを書いてますね。そして、これを当たり前のことだと思えることが大事です


 では、5進数と10進数の2つを同時に考えてみましょう。紛らわしいので、5進数は(124)のように、10進数は(124)10のように表現します。

 小学校の時に、

219=100×2+10×1+1×9

というようなことをやった覚えがあります。当時は「そんな当たり前のことを何でいちいちするんだ」と思いましたが、これはn進数を理解するときに助けになります。

 たとえば、(324)を分解してみましょう。

(324)=(100)×3+(10)×2+1×4

となりますね。(10)とは、(4)の次の数です。つまり、(5)10の事になります。(100)は、(10)×(10)なので、(25)10になります。

 よって、上の式は

(324)=(25)10×3+(5)10×2+1×4

と書き換えることが出来ます。つまり、(324)=(89)10になります。このようにすれば、5進数から10進数へ簡単に変換出来ることが分かります。


 では、10進数から5進数を簡単に求める方法を考えてみましょう。

 さて、何の疑問もなく

(324)=(100)×3+(10)×2+1×4

という式を作りましたが、これは次のような手順をもって作ったとも考えられます。

 先ず、(324)÷(10)を行います。すると、(32)...(4)になりますね。この余りが(1)の位に当たります。

 今度は次に、その時の商(32)を(10)で割ります。すると、商が(3)になり、(2)が余りになります。そして、この余りが今度は(10)の位に当たります。

 で、さらに、今度の商(3)もついでに(10)で割ると、商はもちろん0になり、余りは(3)になります。この余りが(100)の位に当たります。

 (1)の位、(10)の位、(100)の位というのは、このような計算から求められるのです。

 「何を回りくどいことを」と思うかも知れませんが、こうやれば各位が求められることは分かるでしょう。

 さて、ここからが本番です。ここで上の文の5進数で表記されている部分を10進数に直してみましょう。ただし、「(1)の位」とかいう部分は除きます。すると、以下のようになります。

 先ず、(89)10÷(5)10を行います。すると、(17)10...(4)10になりますね。この余りが(1)の位に当たります。

 今度は次に、その時の商(17)10を(5)10で割ります。すると、商が(3)10になり、(2)10が余りになります。そして、この余りが今度は(10)の位に当たります。

 で、さらに、今度の商(3)10もついでに(5)10で割ると、商はもちろん0になり、余りは(3)10になります。この余りが(100)の位に当たります。

 (1)の位、(10)の位、(100)の位というのは、このような計算から求められるのです。

 これが10進数から5進数を求める方法です。0〜4までは5進数でも10進数でも同じなので、上のことから(89)10=(324)という事が分かりますね。


 上では5進数を例にとって考えましたが、このことは何進数にでも適応できます。前者は進数の小さいものから大きいものへの変換、後者は進数の大きいものから小さいものへの変換にあたります。

 ということで、いよいよ2進数と16進数の話に進みます。

 「コンピューターは0と1を使って数値を表現している」と第21章で話しました。これは「0と1という2個の数字を使って数値を表現している」ことになるので、2進数です。つまり、上の文は「コンピューターは2進数を使って数値を表現している」と書き換えることが出来ます。

 しかし、0と1だけで数値を表現すると、例えば(12345)10=(11000000111001)となり、非常に長くなってしまいます。これでは人間にとってはあまり実用的ではないので、プログラムをするときは8進数か16進数を使います

 16進数は0〜9だけでは数字が足りないので、A〜Fの6個のアルファベットを「数字」と見なして使います。「0〜Fという16個の数字を使って数値を表現している」わけです。

 (10)=(1000)で、(10)16=(10000)です。つまり、8進数では2進数の3桁が丁度1桁に対応し、16進数では2進数の4桁が丁度1桁に対応します。

 え? 唐突すぎるって? では、(10010101)を例に取ってじっくり考えてみましょう。


 では、先ず(10010101)を8進数に直してみましょう。先にやった変換方法をちょっと変則的にした方法で直します。

 さて、やはりここは分解です。(10010101)

(10010101)=(1000000)×(10)+(1000)×(010)+(1)×(101)

のように分解できます。

 さて、もう分かりましたね。(1000)=(10)と言いました。すると、(1000000)=(100)になります。(10)=(2)、(101)=(5)なので、上の式は

(10010101)=(100)×(2)+(10)×(2)+(1)×(5)

となり、(10010101)=(225)となります。

 これは、(10010101)を3桁ずつ区切って(10:010:101)とし、各ブロックを変換したのと同じ事になります。

 16進数でも同じ事です。(10010101)を4桁ずつ区切って(1001:0101)とし、各ブロックを変換すると、(95)16となります。まぁ、各ブロックの変換はしなければなりませんが、10進数と比べるとずいぶん変換しやすいことが分かります。


 C/C++言語では8進数と16進数を表現できます。8進数は頭に「0」をつけて、16進数は頭に「0x」を付けて表現します。16進数のA〜Fは大文字でも小文字でも構いません。

num = 214;  // 10進数
num = 0326; // 8進数
num = 0xD6; // 16進数

 ただ、残念ながら2進数は表現できません。8進数か16進数に直して表現しなければなりません。

 また、8進数だと8桁の2進数、つまり1バイトの数値をブロックに分けると2桁:3桁:3桁という形になり、16進数だと4桁:4桁という綺麗な形になることが分かります。2,4バイトの数値になると8進数では1バイト目と2バイト目,2バイト目と3バイト目の間に区切りが来ません。ということで、プログラムでは主に16進数を使います

 ではこれを実際にどう活用するのか...は次回以降にまわして、今回はこのくらいで終わりにします。


 では今回の要点です。


 今回はかなり長くなってしまいました。次回はもう少し短くしたいと思いますが...。では、次回まで。


第44章 いろんな計算を | 第46章 ビットでいじろう

Last update was done on 1999.11.23

この講座の著作権はロベールが保有しています