見出し画像

2進数を習いたての人へ

以下の文章は厳密さなどを捨て、ふんわりと書いたことをご了承いただければ幸いです。こう考えたらちょっとは楽かもよって言いたいのを長ーくしただけです。

イメージできることの重要性

2進数は今までの日常生活で触れたことない数である。
5と言われれば頭の中に何かしらの物体が5つ存在するような映像が頭に浮かぶ。しかし、(0101)と言われても同じように映像が浮かぶだろうか?

5+3=8と言われれば頭に何かしらの物体が5つあってそこに更に3つ追加されるような映像が頭に浮かぶ。
しかし(0101)+(0011)=(1000)と言われても同じように映像が浮かぶだろうか?

2進数で日常でモノを数えるなんてことは基本やらないのだから(0101)と現実世界における5個とリンクしていない。だから10進数に置き直して考えると、イメージはつくが2進数から直接映像への変換はできていない。

14という数字を見たとき10個と4個に分かれた何かしらをイメージする。14という量を直感的に理解できる。しかし(1110)と言われても分からんのである。

世界が2進数で動いていれば、(1000)と(0100)と(0010)に分かれた何かしらを皆が想像できる。だが現実は10進数であるが故に、14を10と4に分けることに違和感はなくとも8と4と2に分けることには違和感を覚えてしまう。これは経験を積むことでしか克服できない。2の指数の値を基準に物を見ていく訓練を積むことでやっとイメージがつくようになる。

イメージが掴めればイメージを掴むための変換行為が必要なくなるため、思考速度は劇的に上がる。

例えば、「歩く速さが大きい人のほうが、同じ時間が与えられた場合に進む距離が大きい。」を考える。
移動距離L=v×tでtが一定ならL/v=(一定)
分母が大きくなれば分子も大きくなる必要があるから速さが大きい人のほうがより長く移動できる!
と式を持ち出して考え込む人は少ないはずだ。

もっと雑に、はえー方がよりずんずん進んでくんだからあたりめーだろ!
と思うはず。

これは速く歩く人と遅く歩く人を想像し、徐々に速い人が遅い人を引き離していくような映像が頭にあり、直感的に理解しているからである。

上記の映像を想像することなく速度公式を持ち出して式変形して動かしてみて、得られる数学的な情報のみで判定する人は少数だと個人的には思っている。

このように、イメージというのは理解を深める上で非常に重要である。
記憶にも残りやすくなり、使いこなすことができるようになるのもこれが重要だと個人的に思っている。(だからイメージしづらい量子力学で私は悲鳴を上げることになるわけですが、、、)

「2の補数の求め方」の説明のピンとこなさは異常

理系に進むと10進法以外の計算に出くわすことになる。特に2進数の加減算において減算や負の数には補数の話が出てくる。

「全てのbitを反転させて1を加えると2の補数だよ!!」

と言われても最初はピンとこない。特に1加えるが本当にピンとこない。IQの高い人は直感で「なるほど!!」ってなるのかもしれない。しかし私のような経験の蓄積を必要とするタイプの人間には、「なるほど!!」を得るまでに時間を要してしまう。

ここで本来はピンとくるまできちんとお勉強する必要があるが、大多数にとっては暗記可能な手順となる。したがって2の補数の求め方はとりあえず暗記となり、しばらくすると「どうやるんだっけな・・・」ということになってしまう。そもそも2進数自体日常ではなじみのない表記形態である。

感覚的には知らん言語で算数やらされてるようなものである。

はえーー!10が2なんか!!!
110111011101 = 3549 = DDD
デデデじゃんははは!!!とかなるまでにはこのよくわからん表記と向き合っていく必要がある。

補数とは

そもそも補数とはなんぞ。

例えば4と96の関係に注目すると合計すると100となる。
1の位がまず10になり10進数の世界では繰り上がりとなる。そしてこの繰り上がりによって10の位も10となり繰り上がりが発生する。最終的に2桁から3桁へ桁上がりする。

このように10進数においてある自然数Xに足すと桁上がりを発生させる最小の自然数Yを「Xの10の補数はY」と言ったりしている。

「最小の自然数」なので96にとっては10の補数は4だが、4にとっては10の補数は6である。これは注意したい。

もう一つ9の補数というものがある。
10の補数は元の数に加えると10となり桁上がりを促す数であるのに対し、9の補数は元の数に加えると桁上がり一歩手前の状態となる数のことである。
小学生の好きな99999…..みたいな数を実現するために必要な数である。
すなわち96の9の補数は3である。

しかし、この補数の考え方自体は小学生の計算の工夫を考える時でもやっていたはずなのだ。そして補数は習ってないものからすれば神業としか思えないそろばんでも根幹を成すキーワードである。

補数を求める行為は小学生の頃の計算の工夫でもやってるはず

補数を求める行為自体は小学生のころからやっているはずなのである。また最上位桁を無視するという行為も別の方法で役立てている。

例えば17-9を考える。
このとき私はまずこれは繰り下がりが発生することを認識する。
発生しなければ1の位の減算を実施するのみ。
今回は繰り下がりが発生し10の位が1であることから桁下がりもするので、
9は10に1足りないから17の7に1を足して7+1=8だ!と答えを出す。

これは
17 - 9 = 17 + 1 - 10 = 8
となる。
10の補数を利用して減算を加算に置き換えたため、最上位桁へ余計な値を残してしまう。繰り下がるはずだったものをきちんと繰り下げるための-10である。

79 + 83であれば
80+83-1=162と計算する。

153 - 78であれば78の10の補数を考えて加算に置き換え
153 + 22 - 100 = 75と計算できたりする。

このように小学生で習う繰り上がり・繰り下がりの計算や「工夫して計算しよう」関連のトピックは、いくつ加えたり減らしたりすればキリのいい数字になるかを考えることに繋がるため補数を考える機会が頻繁に訪れる。

そろばんにおける補数

そろばんでも補数は大活躍する。
ひとつ串に五珠が1つ、一珠が4つで0~9を表現できる。
ここで2+9を考える。

そろばんではひとつの串に9を超える値を格納することはできない。
また、そろばんで1つずつ珠を入れながらカウントしていくわけではない。
足す数の10の補数を考えるのである。
この場合9の10の補数1を考える。
すると2 + 10 - 1となる。
10というのは左隣の串の一珠を1つ入れる行為に相当する。
-1は既に入ってる2から1を取ることに相当する。

このようにそろばんでは補数を利用して計算を進める。

2進数の世界の負の数

話を2進数に戻す。
なぜ2進数の加減算の話になると突然補数という用語が飛び出てくるようになるのか。

そもそも10進数では負の数を「-」で表記する。
-2は-2である。
しかし2進数の世界では2の補数表現であれば10進数の-2は4bitで表記すると
(0010)を反転し(1101)としたものに1を加えた(1110)となる。
-0010とは表記しないのである。

これは計算機が足し算しかできないためである。
「2-2=0」は「2+(-2)=0」と解釈させる必要がある。
「12-7=5」は「12+(-7)=5」と解釈させる必要がある。

この負の数というものをどのように表現すればよいのか。
これには表現可能な桁数が関係する。
ここが事態をややこしくしているのである。

桁数の制限を加える

我々は基本的に有限桁の計算をしていることに着目する。
10進数の計算では桁数の上限というものを気にすることなく計算しているが、計算機内では表現可能な数値の範囲が定まっている。

プログラミングに触れた方はご存じかもしれないが、
int型、double型など数値を格納するための変数にも様々な型が存在する。

例えばint型(符号付整数型)は多くの場合32bitと決まっており、2進数で32桁の数値を表現可能である。この場合は-2,147,483,648 ~ 2,147,483,647である。電卓などで計算すると値が小さすぎるか大きすぎるかでErrorになった経験はあるかと思う。

(-)を使わずに表現する2進数の負の数はこの計算機の表現可能な桁数に上限があるという特徴をうまいこと利用している。

ここで表現可能な10進数は2桁としてみる。
すると101という数字が出てきたとき表現可能なのは2桁なので3桁目は無視して01というのが認識する数字になる。
2桁しか表現できない条件下では98+4= 02となる。
2桁しか表現できない電卓があったとするとこれはError表示になる。
しかしよく考えると、、、

お・・・???
加算したはずなのに答えは足す前より小さくなっている。
つまり98+4という計算が98-96を表現したことになる。
2桁同士の足し算では99+99=198が最大値であり100の位が2になることはない。したがって3桁目を無視するという操作は100を引く操作に等しいということになる。

これらをまとめると
=98+4-100
=98-96
=2
となる。

桁上がりの関係と桁上がり一歩手前の関係

ここで
96に対して10の補数は4
96に対して9の補数は3
差分が1か・・・・

つまり10の補数というのは9の補数を求めてから1足すのか。
お・・・?この操作はもしや・・・?

見えてきた1を足す行為の意味

2進数にて2の補数は「bitを反転して1を足す」操作を経て得られる。
上記では10進数にて10の補数は9の補数を求めて1を足せばよいことが分かっている。

ここから分かるのは、
2の補数は1の補数を求めて1を足せばよい
ということである。

1の補数とbit反転

じゃあ2進数における1の補数って?
簡単です。足すと各位が1になり桁上がりの準備が整う数のことですね。

2進数の世界では0と1しか存在しない。
足して1になれば良いので
・0に対する1の補数は1
・1に対する1の補数は0
が分かる。

あらら・・・・?
これはまさにbit反転。

(00011110)を桁上がり一歩手前にするには
(11100001)を加算すればよいはず。
(11111111)になり、
次に1加算すれば(100000000)と桁上がりする。

したがって(00011110)の1の補数はbit反転した(11100001)となる。
じゃあ2の補数はこれに1足せばいいはずだから(11100010)となる。
もう一度2の補数は何だったか思い出そう。
そう、元の自然数に加えると桁上がりを発生させる最小の自然数である。

求めた2の補数で減算を加算に置き換え

同様に98-96を考えよう。
1byte(8bitのうち1bitを符号に回す)あれば-128~127を表現できるから今回は2進数で8桁を認識可能な桁数としよう。

まずは2進数変換
・98 = (0110 0010)
・96 = (0110 0000)
ここで
◇96の9の補数は3
◆(0110 0000)の1の補数はbit反転して(1001 1111)
共に足し合わせると99と(1111 1111)となり、
桁上がり一歩手前になることが確認できる。

次に10の補数と2の補数を求める。
96の10の補数は3+1=4
(0110 0000)の2の補数はbit反転して1を加えるので(1010 0000)
10の補数と2の補数はそれぞれ10進数, 2進数の世界で桁上がりを発生させる最小の自然数である。

そして桁上がりして新たに増えた桁は「認識できない」のだから無視する。
この「認識できない」は算数的には最上位桁を0にすること。
これはそれぞれの世界で以下の操作を実行することに等しい。
◇2桁10進数の世界では最終的に100を引く。
◆8桁2進数の世界では最終的に(1 0000 0000)を引く。

それでは減算を加算に置き換えよう。
◇98-96=98+4-100
◆(0110 0010) +  (0110 0000) = (0110 0010) + (1010 0000) - (1 0000 0000)

それぞれ計算しよう。
◇98-96 = 102 - 100 = 2 
100引くことで数式上で最上位桁を無視したことを表現している。
◆(0110 0010) +  (0110 0000)
= (0110 0010) + (1010 0000) - (1 0000 0000)
= (1 0000 0010) - (1 0000 0000)
=(0000 0010)
(1 0000 0000)引くことで数式上で最上位桁を無視したことを表現している。

このように補数とその時に必要な桁数が有限であることを利用して、うまいこと加算に置き換えているのだ。

96の10の補数は4とすぐわかるのに2進数ではすぐにわからない。

これは単純に2進数表記を見てから具体的な数をイメージするまでに時間を要してしまうからだ。そこでbit反転という分かりやすい特徴のある1の補数を求めてから1を加算することで2の補数を求めるという手順で説明されることが多いのであろうと自分勝手に推測している。確かに反転は分かりやすくその後に1を足すという操作も難しくない。しかしbitを反転し1を加えた数が減算を加算に置き換えてくれるんだ!というところまでを理解するにはちょっとだけ踏み込む必要がありましたとさ。

駄文を最後まで読んでくださりありがとうございました。


この記事が気に入ったらサポートをしてみませんか?