さて、コンピュータが2進数の世界で動いていること、
さらに、たかが2進数であっても、想像以上に表現力が高いことも理解できた。
これらの知識があれば、少なくとも、ディスプレイに文字を表示するくらいはできる。
では、次の段階として、2進数で算術演算する方法について整理してみる。
いや、正確には、本来は算術演算から説明すべきであるが、
小難しい話を回避するために、話を置いておいたのである。
イメージしにくい事も多いかもしれないので、つまり以下のことさえ解れば良い。
2進数で「数字」を表すことと、2進数で「数値」を表すことが根本的に異なること。
これまでの話を、じっくりと思い出すとこの意味は簡単に理解できる。
例えば、「128」という10進数の「数」があったとする。
これを2進数の数値に変換すると以下のようになる。
1000 0000
半角の「数」の場合、UTF-8 もShift JIS もASCIIコードに対応する。
したがって、このASCIIコードに対応させて「数」を表すことができるはず。
すなわち、「1」と「2」と「8」という三つの文字として表現ができる。
128=[0x31][0x32][0x38]=[0011 0001][0011 0010][0011 1000]
同じ「128」が全く異なる「1」と「0」の組み合わせで表現されていることが重要。
ASCIIコードにおける「数」というのは文字と同様に「数字」であって、
10進数や16進数に変換可能な2進数としての「数値」では無いのである。
これでは、少々、困ったことになる。「数字」というのは、コンピュータ上で、
「足し算」、「引き算」、「かけ算」、「割り算」といった「四則演算」ができない。
「少々」というか、いや、かなり困ったことになる。
本来、コンピュータというのは、数値を計算することを目的に開発されたが、
四則演算が出来なければ、コンピュータの本来の存在意義がなくなってしまう。
やはり、計算する際には「数値」として2進数を扱う必要がある。
さて、以上のことを理解できれば、これ以上の話をする必要は無いのであるが、
実際の計算方法を知っておけば、後の話である「データ型」の話が解り易いし、
何より、将来的に、自分で何かを作り出す際に色々と役立つかもしれない。
何事も「色々と考えてみる」ことが重要。とりあえず、2進数の計算に挑戦してみる。
コンピュータ上では、もっとエレガントな方法で計算するのであるが、
ここでは、基本的な2進数の計算から入ることにする。
途中で「ダメ」だと感じ人は、データ型の話に進んでも構わない。
まず、基本的なこととして、2進数も「数値」であるので、
10進数と同様に計算することができる。このセンスが重要。
このことは、観念的にも理解できるので大丈夫であろう。
問題は、日常的に用いる10進数の計算とは少々異なること。
慣れないと難しいかもしれないし、実際に、
高校の数学で2進数が登場した時に挫折した人は少なく無い。
ということで、ここで改めて2進数の仕組みを思い出してみる。
たしか、「2」になる時に繰り上がるような仕組みだった。
繰り上がりさえ間違えなければ、基本的な加算と減算に関しては10進数と同じ。
実際に、人が2進数で計算することは非常に稀ではあるが、
まずは、「足し算」と「引き算」をやってみる。結論を先に言うと、
2進数で計算した後に、計算結果を10進数に戻しても正しい結果が算出される。
0000 0011 + 0000 0001 = 0000 0100
0000 0011 - 0000 0001 = 0000 0010
実は、上の二つの計算は、それぞれ、「3+1」と「3−1」であった。
その計算結果だったので、上の計算結果が「4」で、下の計算結果が「2」となる。
ちゃんと、2進数で計算した後に、結果を10進数に直しても計算結果は一致する。
なるほど。ややこしいように見えるが、まぁ、難しいと言っても知れている。
手計算で計算するのは、少々、混乱するかもしれないが、
計算機を使えば、計算間違いをすることも無い。
では、かけ算と割り算になると?これは少々厄介である。
厄介ではあるけれど解ると面白い。不思議が一杯。
とりあえず、以下の2進数を10進数に変換してみる。
0000 0001 = 1
0000 0010 = 2
0000 0100 = 4
0000 1000 = 8
0001 0000 = 16
0010 0000 = 32
0100 0000 = 64
1000 0000 = 128
さて、ここでは、1bitずつ左側にずらしているだけであるが、
これを見て、何かの「規則性」に気付きはしないだろうか?
良く見ると、何らかの法則が見えるはず。高校の数列の問題に似ている。
そうそう。左側にシフトしてやると「2倍ずつ」増加している。
逆に、右方向にシフトしてやると「2分の1ずつ」減少するとも言える。
次に、初期値を変えて計算してみる。この法則は適用できるだろうか?
0000 0101 = 5
0000 1010 = 10
0001 0100 = 20
0010 1000 = 40
0101 0000 = 80
1010 0000 = 160
やはり、左側にシフトすると「2倍ずつ」増加し、
したがって、右側にシフトすると「2分の1ずつ」減少する。
さらに、以下の場合はどうなるのか?割り切れない場合の右シフト。
0001 1111 = 31
0000 1111 = 15
うん?この状況は、いまいちよく解らない。何が起きているのか?
良く見ると、右端の「1」がどこかに行った。捨てられている。
つまり、どのような状況であるのか?では別の例で考えてみる。
0101 0101 = 85
0010 1010 = 42
どうやら、2で割って余りを切り捨てているようである。
一般的な式で表すと、元の数をxと置き、シフトの回数をnとすると、
左シフト「」と右シフト「」は、以下のように表現できる。
二つ目の式は、少々、見慣れないかもしれないが、
要するに、2で割った値の整数部分のみを取るということである。
「余り」という考え方をすると、「余り」を切り捨てていることになる。
このような、2進数における独特な演算方法を「シフト演算」と呼ぶ。
さて、ここで一つの疑問が生まれる。「3倍」や「15倍」の場合はどうするべきか?
もっともな疑問である。実際に、これらが出来ないと困る。
実は、これらの掛け算の場合は、足し算の方法と組み合わせるのである。
まずは、「5×3」というのを考えてみる。
これは、「5(2+1)=(5×2)+(5×1)」と考えることができる。
2倍というのは1bit左シフトなので、以下のように計算できる。
0000 1010 + 0000 0101 = 0000 1111 = 15
では、「5×15」の場合はどのようになるのか?
これは「5(8+4+2+1)=(5×8)+(5×4)+(5×2)+(5×1)」に「分解」できる。
つまり、「2の3乗」と「2の2乗」と「2の1乗」の組み合わせ。
0010 1000 + 0001 0100 + 0000 1010 + 0000 0101 = 0100 1011 = 75
というように計算することができる。
このようにして、演算することで2進数の掛け算をすることができる。
普段、我々が行っている10進数の計算方法とはかなり異なっている。
さて、割り算も...と話を進めたいのであるが、
残念ながら、これは掛け算と同じようには行かない。
もう少し、複雑な方法で計算しなければならない。
この方法は、足し算、引き算、掛け算とは異なり、
少々、エレガンスに欠けるのであるが、
要するに、筆算を解くようにして計算する。
ここでは「5÷3」を考えてみる。これまで表記通りに2進数で表すと、
以下のようになる。
5÷3 = 0000 0101 ÷ 0000 0011
本質的には同じなのであるが、割り算の場合、桁数がポイントになる。
この表記では、少々、見難いので、前のゼロの部分を取り除いて、
まずは、以下のように表記することにする。
5÷3 = 101 ÷ 11
筆算のように表すと、以下のようになる。ここまでは大丈夫であろう。
11)101
ここで、割られる方が「101」で、割る方が「11」であることを確認し、
割られる方の桁を一つずつ増やしながら、引き算をし、引き算が可能な場合には「1」を、
引き算が不可能な場合には「0」を解にセットしていく。
なんとも、言葉では表現しにくい。
まず、割られる数の「101」の前から二つを取りだした「10」と、
割る数の「11」を引き算してみる。
10 - 11 = 引くことができないので「0」をセット
したがって、筆算の方式で表すと次のようになる。
10進数と同様に、「11✕0=00」を「10」の下にセットする。
0
11)101
00
101
次に、割られる数の桁を一つ増やして、「101」から「11」を引く。
今度は、引き算が可能が可能なので「1」をセットする。
101 - 11 = 引くことができるので「1」をセット
同様に、筆算の形式で書いてみる。今度は、上に「1」がセットされ、
「11✕1=11」を「101」の下にセットし、引き算する。
01
11)101
00
101
11
10
引き算した結果は「10」となり、これが「余り」となる。
つまり、「101÷11=1・・・10」が解となる。これを、10進数に戻すと、
「1⇒1」で、「10⇒2」となるので「1余り2」となり、正しい答えが得られた。
このように、2進数の四則演算は、10進数の四則演算と密接なつながりがあり、
2進数で計算した結果を10進数に変換すると、10進数同士で計算した結果と等しくなる。
この当たり前のことを、実感として理解することは極めて重要なのである。
この性質のおかげで、コンピュータは、「1」と「0」しか扱うことができなくとも、
複雑な計算ができるのであるし、また、「データ型」という厄介な問題が出てくるのである。
0 件のコメント:
コメントを投稿