二進数と手をつなぐための2つのコツ(といくつかの豆知識)

| コメント(0) | トラックバック(0)




  1. 十進数と相互に変換する

  2. 十六進数と相互に変換する

  3. 豆知識


コンピュータの世界で中心に座する二進数は、ちょっとしたコツを掴むと一気に使いやすくなる。


「プログラミングは好きだが、二進数の扱いが苦手・煩わしい」と感じている方はご参考までにどうぞ。ある程度経験のある方にはお目汚しになると思うが、よろしければ誤りなどご指摘頂けると幸いです。


十進数と相互に変換する


例えば二進数の計算式を解かなければならないとしたら、選択肢はふたつある。



  1. 二進数のまま筆算する

  2. 別の基数に変換して計算し、二進数に戻す


前者でももちろんできるが、慣れない計算だけに速度も落ちるし、ミスの危険性も高まる。そこで、最も慣れ親しんだ基数に変換して計算して、そのあとで二進数に戻すことを提案する。


我々が最も慣れ親しんでいる基数といえば、間違いなく十進数である。二進数から十進数へ、またはその逆の変換をスムーズに行えれば、十進数の計算で間違えることはまずないだろう。そこで、まずは二進数と十進数の間での変換が重要であると考える。


各桁をフラグとして扱う


基数の変換にはいくつか一般的な方法がある*1が、これらの手順は煩雑で手間のかかるものであることが多い。それはこれらの方法が、何進数からでも十進数に変換できるよう、一般化されているからである。例えば八進数や十六進数、二三進数なんてものからの変換も可能である。それらを全てひとつの式で扱えるようにするため、式自体は少し複雑になっている。


つまり変換対象の基数を二進数に限れば、これほど煩雑な計算をする必要はない。


最も直感的な方法は、二進数の各桁をフラグとして認識することである。


f:id:Tnzk:20071111140253p:image


上図は、各桁が持つ数値*2をカードとして表現したもの。各桁が1ならカードは存在し、0なら存在しない。カードの数値を足し合わせれば、その二進数が表す十進数値が得られる。


1111 1111の場合、全桁が1なので全てのカードが存在している。それらを足し合わせると128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255となる。


f:id:Tnzk:20071111141948p:image


0000 1011の場合。8と2と1が存在しているので、値は11となる。


f:id:Tnzk:20071111142231p:image


0101 0010。64 + 14 + 2で82。


カードの数値を覚える


フラグとして考えて、それらを足し合わせる手法がだいたい身についたら、次は各桁のカードの値を覚える。


必ずしも覚える必要はない。最も下の桁を1として、上に進むごとに2倍していけばカードの値は得られる*3。8桁目まで(1byte分)くらいは暗記しておくと便利か。


十進数から二進数への変換


逆に十進数から二進数への変換はというと、観念的には、



  1. カードを並べる: 何桁くらい必要か見繕う

  2. おおまかに数値を近づける: 大きい桁から、オーバーしないようにフラグを立てる

  3. 細かく修正する: 小さい桁で細かい値を調整したり奇遇を決める


といった流れで行うのが易い。


1. カードを並べる: 何桁くらい必要か見繕う


何桁使うかを考えておく。ただし厳密である必要はない。多すぎても小さすぎても、次の手順2で少し余分の時間が必要になるだけ。逆にここで厳密な桁数を算出するほうが時間を使うことが多い。


2. おおまかに数値を近づける: 大きい桁から、オーバーしないようにフラグを立てる


細かいところは次の手順3でこなすので、ここではおおまかにあわせる。


531なら、10桁目の値が512なので、531 ≒ 0010 0000 0000(2)とする。


3. 細かく修正する: 小さい桁で値を調整したり奇遇を決める


先の手順2で得られた0010 0000 0000(2)( = 512)は、当然厳密ではない。531 > 512なので、不足分を加えて完成する。


不足分は19。19に対して手順2を適用すると、5桁目の値16が近いので19≒0001 0000(2)( = 16)。


さらに不足分を補う。19 - 16 = 3で、3 = 11(2)。ここまで値が小さくなると空で変換できる。


ここまでで得られた、0010 0000 0000, 0001 0000, 0011を全て足し合わせる*4


すると0010 0001 0011(2) = 531(10)となる。


十六進数と相互に変換する


十六進数との変換はより簡単。二進数の4桁の範囲は、十六進数1桁の範囲にちょうど合致する。ここまで私が二進数を書くときに、4桁ごとに空白で区切ってきたのはそのためである。


ぬるいケース


先程算出した531(10) = 0010 0001 0011(2)を例に取ろう。


下4桁、0011(2) = 3(10)。3は十六進数でも3でしかないから、これは3。中4桁もそのまま1。上4桁もそのまま2。


ということで213(16)となる。


らしいケース


あまりにも例として価値がない(せっかく十六進数なのにアルファベットが出てこないのは寂しい)ので0010 1101 0011(2)の場合も示す。0010 0001 0011(2)との差は0000 1100 0000(2) = 192(10)だから、723(10)。


下4桁、上4桁はやはりそのまま3と2。


事情が異なるのは中4桁。1101(2)は13(10)だから、そのままでは2桁。これをそのまま据えて2133(16)では値がまったく異なってしまう。


十六進数では十進数で10~15の値を1桁で表すことができ、順にa, b, c, d, e, fが割り当てられる*5


13(10)はd(16)。ということで、0010 1101 0011(2) = 2d3(16)となる。


豆知識


二進数の扱いについて、有名な豆知識がいくつかある。



  • 1桁目が1の場合、奇数。0の場合偶数。*6

  • 全桁を左に1桁ずらすと2倍、右に1桁ずらすと1/2倍。*7

  • 二進数3桁は八進数1桁に対応する。


参考


16進数




*1基数変換:ITpro


*2:一般的に桁の重みといわれるもの


*3:n桁目の重みは2の(n-1)乗


*4:足し合わせるといっても、繰り上がりは発生し得ないので論理和をとると考えてもいい


*5:アルファベットは便宜的なもの。独立した記号があってもいいはずだけど普及したという話は聞かない


*6:1と論理積をとって0なら偶数、1なら奇数


*7:左シフトと右シフト


トラックバック(0)

トラックバックURL: http://www.tnzk.org/mt/mt-tb.cgi/140

コメントする

このブログ記事について

このページは、tnzkが2007年11月11日 16:51に書いたブログ記事です。

ひとつ前のブログ記事は「そんな風にすごしたい」です。

次のブログ記事は「どうやら合格」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

Powered by Movable Type 4.32-ja