コンピュータは2進数を使ってるみたいな話を聞いたことがある人は多いと思う。むしろよく知らない人からすれば、2進数なんて聞くのはコンピュータ関連の勉強をするときくらいだろう。
だとしたら、2進数とはコンピュータ用語なのかと言うとそんなことはない。現代コンピュータが2進数をそこそこ利用しているというだけの話だ。
実際問題として、現代コンピュータの動作を理解しようとするなら2進数について知っておくと有利だと思う。ハードウェアでは2進数を抽象化して表現している部分もあるし、ソフトウェアの設計やアルゴリズムでその性質を利用しているものもある。まぁとりあえず、知らないよりは知っていた方がいいと思う。
そういったわけで、今回はコンピュータの話は置いておいて、そもそも2進数とはなんぞやということを考えてみたい。
進数と進法の違い、というかそもそも数って?
この手の話ではお約束なので一応言っておくと、2進数とは「2進法で表した数」のことだ。言葉尻を捉えてあげつらうような話だが「進数」と「進法」は用語として別物ということだ。まぁよく混同されるのでフォーマルな場面でなければ気にしなくて良いだろう。
ちなみに、10進数とか16進数というものも聞いたことがあるかもしれないが、これも10進法とか16進法で表した数ということだ。とりあえず、以下ではそれらをひっくるめてN進数とN進法ということにする。
ところで「N進法で表した数」という言葉には「N進法」という要素と「数」という要素が含まれている。念のため「N進法」の前に「数」について確認しておこう。
あまり意識して考えたことがないかもしれないが、「数」というのは目に見えたり聞こえたり触ったりできない純粋な概念だ。
例えば「3」と紙に書いてあったとしても、それは3という「数」そのものではなくて「3」という形の模様だ。紙やその模様に手を触れることはできても、それは3そのものを触ったことにはならない。リンゴを3個持っていても触っているのはリンゴだし、水を3リットル持っていてもやはり3そのものではない。
つまり、3という数は意識の中にしか存在しない、ということを認めないといけない。
その上で他人に伝えたり記録しておくために、どうにかこうにか物体として表現するための方法の1つが「3」という字なわけだ。他にも「三」や「?」と書いたり、声で「さん」や「スリー」と言ったり、物を3個置くとか指を3本曲げるとか、3を表現する方法はいくらでも存在する。
そんな色々ある方法の内の1つがN進法というわけだ。
日本語の数え方
N進法について考える前に、次は「数え方」というものを考えてみよう。身近な例として現代日本語の一般的な数え方を考えてみてほしい。
読みにくいかもしれないが漢字で書かせてもらうと、
- 一、二、三、四、五、六、七、八、九、十
- 十一、十二、十三、十四、十五、十六、十七、十八、十九、二十
- 二十一、二十二、二十三、二十四、二十五、二十六、二十七、二十八、二十九、三十
となっている。
これで特に違和感もないだろうが、理解のために区切り位置を変えてみよう。「十」が次の行に来るようにして、数合わせでゼロを先頭に入れると見た目が揃う。
- 〇、一、二、三、四、五、六、七、八、九
- 十、十一、十二、十三、十四、十五、十六、十七、十八、十九
- 二十、二十一、二十二、二十三、二十四、二十五、二十六、二十七、二十八、二十九
「十」は「九」の次の数だが、それまでの一から九とは性質が異なっていて「十」は「一」が10個ひとまとまりの単位と捉えることができる。「二十」は「十」という単位が2個分ということだし「三十」なら3個分だ。そして、その「十」が10個で「百」という次の単位になって、「百」が10個で「千」だ。
N進法
このように10個ひとまとまりで次の単位に進むような数え方を10進法という。
なので日本語の数の数え方は10進法なのかというと実はそうでもない。「千」の次は「万」だが、これは「千」が10個の単位というよりも「一」が1万個の単位だ。
もしそのまま10個ずつだとしたら「万」の次は「十万」になってしまうが、45万を「四十万 五万」とは言わずに「四十五万」ということから「十万」は単位ではなさそうだ。
「万」の先は「億、兆、京、垓……」と1万倍ずつ単位が大きくなっているので、日本語の数の数え方は万進法だと言われているようだ。
ともあれ10個ずつなら10進法、万個ずつなら万進法、そして2個ずつなら2進法というわけだ。
命数法と記数法
上の日本語の数え方の文章では数を頑なに漢字で表記していたが、これにはわけがある。
日本語では「1234」という数を「千二百三十四(せんにひゃくさんじゅうよん)」と読むが、これは「1234」という数に「千二百三十四」という名前を付けているのだと考えることができる。
つまり上の文章で確認した数の数え方というのは、ある数をどのように命名するか、という命名規則と捉えることができる。数の表現方法の中でも、このように命名をともなう方法を大きくまとめて「命数法」というらしい。
そんな「命数法」と対比されるのが「記数法」だ。これは数を書くときの方法を大きくまとめたものだ。
算数や日常生活で目にする数字はだいたいがいわゆるアラビア数字だと思う。「1, 2, 3, 4, 5, 6, 7, 8, 9, 0」の10種類の字を組み合わせて使う慣れ親しんだ方法で、いわゆる10進数とはこの方法で表された数のことだ。
かなり世界的に使われているが、「1234」を日本語では「千二百三十四」と読むのに、英語では「one thousand two hundred thirty-four」と読んでいる。つまり書き方は決まっていても、読み方は特に決まっていない。
数の表現方法のなかでも、このように書き方に関する方法を「記数法」というようだ。
位取り記数法
そんな普段から何気なく使用しているアラビア数字を使った数の表し方だが、この方法の特徴は数字の位置で数の単位を表していることだろう。
「1」の位置に注目して欲しいのだが、
\begin{aligned}
1\\
10\\
100\\
1000\\
\end{aligned}
と位置が左に1つずれると、10進法で言うところの単位が10倍になる。
このように数字の位置によって数を表すことから、この方法は「位取り記数法」と言われている。位(くらい)と言うのは、つまり数字の位置のことだ。
ローマ数字のように「I, II, III, IV, V, VI…」と数字の個数や種類で数の大きさを表す方法に比べて、視覚的に数の大小がわかりやすいし計算もしやすい。またどんな大きな数でも数字の種類を増やさずに表すことができる。これはまさに「0」を導入して位置を揃える、という発想の勝利だろう。
なお、今までの説明では単位と言っていたものだが、位取り記数法ではそれぞれの位の大きさを「重み」という。一番右の位の重みは1で、左に10, 100, 1000, …と10倍になっていくだけだ。数学的に表現するなら右からn番目の位の重みは $ 10^{n-1} $
ということだ。
2進数
というわけで、ここまでで普段使用している数の表し方が「10進の位取り記数法」だということがわかった。
10進法は10個で次の単位に進む方法だ。これを位取り記数法と合わせると、10個で次の位に1繰り上がって元の位は0になる。
\begin{aligned}
0\\1\\2\\3\\4\\5\\6\\7\\8\\9\\10\\11\\...
\end{aligned}
0から8までの数を2~10進数で表記すると次のようになる。ここでは区別のために下付きの数字で何進数か表す。
\begin{aligned}0_{10} = 0_9 = \phantom{0}0_8 = \phantom{0}0_7 = \phantom{0}0_6 = \phantom{0}0_5 = \phantom{0}0_4 = \phantom{0}0_3 = \phantom{000}0_2\\1_{10} = 1_9 = \phantom{0}1_8 = \phantom{0}1_7 = \phantom{0}1_6 = \phantom{0}1_5 = \phantom{0}1_4 = \phantom{0}1_3 = \phantom{000}1_2\\2_{10} = 2_9 = \phantom{0}2_8 = \phantom{0}2_7 = \phantom{0}2_6 = \phantom{0}2_5 = \phantom{0}2_4 = \phantom{0}2_3 = \phantom{00}10_2\\3_{10} = 3_9 = \phantom{0}3_8 = \phantom{0}3_7 = \phantom{0}3_6 = \phantom{0}3_5 = \phantom{0}3_4 = \phantom{}10_3 = \phantom{00}11_2\\4_{10} = 4_9 = \phantom{0}4_8 = \phantom{0}4_7 = \phantom{0}4_6 = \phantom{0}4_5 = \phantom{}10_4 = \phantom{}11_3 = \phantom{0}100_2\\5_{10} = 5_9 = \phantom{0}5_8 = \phantom{0}5_7 = \phantom{0}5_6 = \phantom{}10_5 = \phantom{}11_4 = \phantom{}12_3 = \phantom{0}101_2\\6_{10} = 6_9 = \phantom{0}6_8 = \phantom{0}6_7 = \phantom{}10_6 = \phantom{}11_5 = \phantom{}12_4 = \phantom{}20_3 = \phantom{0}110_2\\7_{10} = 7_9 = \phantom{0}7_8 = \phantom{}10_7 = \phantom{}11_6 = \phantom{}12_5 = \phantom{}13_4 = \phantom{}21_3 = \phantom{0}111_2\\8_{10} = 8_9 = \phantom{}10_8 = \phantom{}11_7 = \phantom{}12_6 = \phantom{}13_5 = \phantom{}20_4 = \phantom{}22_3 = \phantom{}1000_2\\\end{aligned}
2進法だと2個で次の位に繰り上がるので、結果的に0と1を交互に繰り返すような見た目になる。
ところで、2進数の「100」は10進数だと「4」と表記するが、これは表記方法が違うだけで全く同じ数だ。なので、2進数で「100」と書かれているものを「よん」と読んでも間違いではないが、あえて2進数で表記されていることを尊重して「いちぜろぜろ」と読むのが一般的だ。
小数
位取り記数法では1の位より右は小数点をつけて表記する。
\begin{aligned}
100\phantom{.000}\\
10\phantom{.000}\\
1\phantom{.000}\\
0.1\phantom{00}\\
0.01\phantom{0}\\
0.001\phantom{}\\
\end{aligned}
10進数では、1つ左の位の重みが10倍になった。逆に考えれば1つ右の位は10分の1ということだ。これが2進数なら2倍と2分の1になる。
10進数の $0.1_{10}$
が $1_{10}$
の10分の1だったように、2進数の $0.1_2$
は $1_2 = 1_{10}$
の2分の1なので $0.5_{10}$
だ。$0.01_2$
なら $0.25_{10}$
だ。 $0.11_2$
はもちろん $0.1_2$
と $0.01_2$
を足した $0.75_{10}$
を表している。
循環小数と有理数
ところで、 $0.1_{10}$
を2進数で表すと $0.0\dot{0}01\dot{1}_{2}$
のように循環小数になってしまう。
\begin{array}{rrrrl}
1_{10} &\div& 10_{10} &=& 0.1_{10} \\
= 1_{2\phantom{0}} &\div& 1010_{2\phantom{0}} &=& 0.0\dot{0}01\dot{1}_{2}
\end{array}
他にも10進数ではキレイに割り切れるのに、2進数ではキレイに割り切れない小数は多い。
10進数でできることが2進数ではできないということは、2進数は不完全なものなのだろうか? もちろん、そんなことはない。
10進数でも3分の1は循環小数になってしまうが、3進数なら $0.1_3$
と循環小数にならない。
つまり、循環小数かどうかは表記の問題であって、数そのものの性質ではない。逆説的だが、循環小数は小数点以下が無限に続くのに「有理数」に分類されるのも合点がいくというものだ。
コンピュータとの関係
これらのことから分かるように、2進数とは単に数の表記方法だった。それなのに2進数はコンピュータで使われているという。
これは2進数(というよりも2進法)が電気と相性が良いから、ということに他ならないのだが、これについてはまた別の記事で。