ビット演算の実習
ふたたびビット演算の話です。
「もういいよ! あんまり使う場面ないし!」と思うかもしれませんが、うん、まあ、いままであんまり使う場面ありませんでしたね。
そこで今回は、もっと役立つビット演算の使い方をいくつかおぼえてみよう、という回です。
これで意外と役に立つものなんですよ。
例によって、これさえおぼえておけば、人のプログラムを読むときにグンと読みやすさがアップしますし。
難しいようで、わかってみるとカンタンなことでもあるので、ANDやORの計算に慣れながら読んでいってみてください。

前回までのサンプルプログラムで、ビット演算が出てきたのはおぼえてるかな?

たしか、A=(A+1) AND 3ってカタチだったよね。

そうそう。コレでどういう効果が出るかは、おぼえてる?

この行を通るたびに変数Aの数が0から1ずつ増えるんだけど、4まで増えたときには0に戻されるんだった、かな?

そういうコトだね。では、このビット演算を……

テメエら、リズムだけでサクサクおさらいするのもイイカゲンにしやがれ! このオレもついてこれてねェぞ!

ヒドいなあ。じゃあ、いまのAND 3がうまく動くしくみを見直してみることから始めるかい。

復習ってのもおベンキョウくさくってあんまり好きじゃねェが……
まず、サイショに変数Aが0だったトキはどうなるんだ?

A=(A+1) AND 3ってことは、言いかえると1 AND 3の計算になるよね。

それを2進数の式にすると、こうなるね。
01
AND 11
= 01
ANDを使った計算はまだ忘れてないかな?

上からメセンがニクニクしいぜ! 同じ位をクラベて、両方1なら答も1、0が片方でもあったら0になるってヤツだろ。

そこまでワカッてるなら一気にいこうか。変数
Aに入る数字が
0から
3までのパターンを並べてみるよ。
それぞれ
+1されるから、
1 AND 3 ~
4 AND 3の式になるね。
01 10 11 100
AND 11 AND 11 AND 11 AND 011
= 01 = 10 = 11 = 000
4 AND 3のときだけ、結果がゼロになるのがわかるだろう。

ホントだな。
ギャクに1~3までは、AND 3されても、そのままナニゴトもなく変化しねェのがフシギだぜ。

そうか、11みたいに全部1で並んだ数でANDすると、数はなにも変わらないでそのまま出てくるんだね。

おっ、いいトコロに目をつけたね。そのとおりで、たとえば
AND 2だと、そうウマくはいかないんだ。
01 10 11 100
AND 10 AND 10 AND 10 AND 010
= 00 = 10 = 10 = 000

タシカになんだか、スッキリしねえケッカになるな。

これが
AND 7だとどうかな?
7を2進数になおすと
111で、
1が並ぶ数字だね。
001 010 … 111 1000
AND 111 AND 111 … AND 111 AND 0111
= 001 = 010 … = 111 0000

やっぱり3ケタまではゼッタイ変化しないで、上の数が4ケタになったとたんにゼロになるよ!

……ANDと1が並ぶ数を使うと、ある数まではフツウに増えて、ある数まで増えたらゼロにリセットされるってコトなのか?

悪くないリカイだよ。
A=(A+1) AND 7が「8回ループするたびに1回だけゼロになる」ものと考えると、IF A==FALSE THENとすれば8回に1度だけトクベツなコトができるね。

かならず8回目にゼロに戻ってくるのもベンリかもね。ON A GOTOを使ったプログラムでも、自動的にループになるよ。

タシカにサンプルプログラムでやったコトも同じか……。
で、111みたく1が並ぶ数ってのはナニとナニがあるんだ? 3と7はワカッたが、いちいち探すのはメンドくせェぜ!

だいじょうぶ、それにはパターンがあるんだ。先にそういう数を見せた方が早いかな?
2進数にすると
1の連続になる数字
10進数 | 2進数 |
1 | 1 |
3 | 11 |
7 | 111 |
15 | 1111 |
31 | 11111 |
63 | 111111 |
127 | 1111111 |
255 | 11111111 |
: | : |

1、3、7、15、31……うーん、パターンがあるような、ないような……

ナンだか数字パズルみたいになってきたな。ニガテなテンカイだぜ!

ゼロから数え始めるコンピューターのクセに合わせて、数を1ずつ増やすとどうかな?

ん? 2、4、8、16、32……あっ! ぜんぶ倍になってるよ!

いわゆる「2のべき乗」だね。その数マイナス1と考えれば、アンガイおぼえやすいだろう。「64」や「256」なんかはゲームでも見たことある数じゃないかな?

64分の1の確率でアイテムをドロップ、とかアリガチじゃな。
コンピューターとアイショウのいい数じゃからのう。ムカシはバキ●ラを256回撃つと倒せるというウワサが……

ケッ、ムカシ話にはキョウミがねえぜ!

ま、まあそれもこれもビットの考えカタにそっとるのじゃよ。

この数だと「63」にVSYNC命令を組みあわせると、こんな風にもできるね。
0001#. @LOOP
0002#. VSYNC 1
0003#. A=(A+1) AND 63
0004#. PRINT A
0005#. GOTO @LOOP

VSYNC 1は60分の1秒だけ待つってコトだろ。それとコレとどうカンケイが……

ビット演算では64回に1回リセットだから……1秒と4/60秒だけループすると変数Aがゼロにリセットされることになるね。

つまり「だいたい1秒」でリセットされるカウンターだね。ここではただのPRINTだけど、ゲームのタイマーや1秒ごとにたまるダメージとか、使いどころはあるんじゃないかな。

オイオイ、「だいたい1秒」って、そんなテキトウでいいのか!?

目に見えるワケではないからのう、体感時間としてはアリじゃ。ぶっちゃけプログラムにはよくある手じゃよ。
その後、プログラムを解析されて「なんちゃって1秒」だとバレるところまでふくめてワンセットじゃ。

は、はかりしれねえセカイだぜェ……。

ン? さっきの「2、4、8、16、32……」って数、マエにも見た気がするな……

そういえば、
BUTTON()命令に使われてる数字がそうだったよ!
十字ボタン↑ | 1 | | Aボタン | 16 | | Lボタン | 256 |
十字ボタン↓ | 2 | Bボタン | 32 | Rボタン | 512 |
十字ボタン← | 4 | Xボタン | 64 | START | 1024 |
十字ボタン→ | 8 | Yボタン | 128 | SELECT | 2048 |

ソレもビット演算の考え方を使ってるんだけど、しくみは飛ばしておぼえていたね。ためしに2進数に直してみるよ。
10進数 | 2進数 |
---|
1 | 1 |
2 | 10 |
4 | 100 |
8 | 1000 |
16 | 10000 |
32 | 100000 |
: | : |

そうか、2進数にするとキリがいい数だったんだな。ソコまではワカったが……コレとビット演算がカンケイあんのか?

これだけだと、まだわかりづらいね。2進数のケタをそろえてみよう。
10進数 | 2進数 |
1 | 000001 |
2 | 000010 |
4 | 000100 |
8 | 001000 |
16 | 010000 |
32 | 100000 |
: | : |
先頭にゼロをつけただけで、数が変わったわけじゃないよ。

ははあ、右からジュンバンに1ケタずつ、ボタンと1のペアができてるんだね。こうやって見ると数字っていうよりは、記号みたいだよ。

タシカに。それぞれのケタがスイッチで、0が「オフ」で1が「オン」だって考え方があるんだ。
だから、こういう表でも1になっているケタを「ビットが立っている」と言ったりするね。

0から1になるのが、「ビットが立つ」ってことか。

000010なら第1ビットが立っている、なんて言うね。1ケタ目が第0ビット、2ケタ目なら第1ビットさ。

またゼロから始める数えカタかよ……ギョウカイ用語はいいから、サッサとハナシをススメやがれ!

じゃあ、たとえば「十字ボタン↑」と「Aボタン」が同時押しされた時で考えてみよう。
10進数なら1+16で17が変数に入るけど、この数を2進数にするとどう見えるかな?

えーと、こうなるかな。
10進数 | 2進数 |
1 | 000001 |
16 | 010000 |
1+16=17 | 010001 |

お、オォ? そのまま組み合わさったみてェな数になったぜ!

こういう「1、2、4、8、……」と倍々になっている数のトクチョウだね。数をたすとビットが立ったままキレイに合わさるんだ。

ますます記号みたいだね。
つまり
BUTTON()命令だと、第0ビットが「十字ボタン↑」のスイッチになっていて、第4ビットは「Aボタン」のスイッチってことだね。
十字ボタン↑ | 1 | 000000000001 |
十字ボタン↓ | 2 | 000000000010 |
十字ボタン← | 4 | 000000000100 |
十字ボタン→ | 8 | 000000001000 |
Aボタン | 16 | 000000010000 |
Bボタン | 32 | 000000100000 |
Xボタン | 64 | 000001000000 |
Yボタン | 128 | 000010000000 |
Lボタン | 256 | 000100000000 |
Rボタン | 512 | 001000000000 |
START | 1024 | 010000000000 |
SELECT | 2048 | 100000000000 |

ナカナカおもしれえハナシだが……だからナンのイミがあるんだって気もするぜ!

ここからがベンリなところだよ。
BUTTON()命令で言えば、Aボタンが押されているかをチェックしたい時はどうするんだったかな?

Aボタンは10進数の
16ってコトだから、IF文で
AND 16をするんだったか……
0000#. @LOOP
0001#. B=BUTTON()
0002#. IF B AND 16 THEN PRINT”Аカ゛オサレテマス”
0003#. GOTO @LOOP

じゃあ、ソコで何が起きているのか、今度はちゃんと見てみよう。
いま出てきた「十字ボタン↑」と「Aボタン」が同時押しされた時の数「
010001」に、
AND 16のビット演算をしてみるね。
010001
AND 010000
= 010000

あっ! Aボタンのスイッチになってる第4ビットだけが立ってるよ!

わかってきたかな。チェックしたいケタに1を、それ以外のケタに0を入れてANDで演算すれば、そのビットが立っているかどうかスグにわかるんだ。
このトクチョウをうまく使ったのが、BUTTON()命令とANDを使ったIF文だね。

ゴクリ……てことは、第5ビットのBボタンが押されてるかどうかで考えると……
010001
AND 100000
= 000000
ヤッパリ答はゼロ、第5ビットは立ってねえってコトがワカるぜ!

「1、2、4、8、……」という数で組み立てておくと、こういうチェックにベンリなのがわかるね。
頭で考えるよりも、こういう数のパターンをひとつおぼえておくといいよ!

フーム……このパターンをBUTTON()命令イガイに使うとすると、トウゼン変数だよな。フラグなんかにベンリそうな気はするぜ!
どうするのがイイのかはサッパリ思いつかねェけど。

スッキリあきらめたね。
まあ、さっきのBUTTON()命令だって、「上ボタンを押すと第0ビットのフラグが立つ」と考えればリッパにフラグさ。その応用で作ればいいよ。

ナルホド、そういうミカタもあるか……。

さすがにBUTTON()なみに11ケタいるとは思えないけど、4ケタあれば、4つのオン・オフをいちどに見られるフラグになるワケだね。

イヤちょっと待てよ! BUTTON()ならボタンを押せばカッテにフラグが立ってくれたがよォ、自分のプログラムの中でフラグを立てたり消したりするのは、どうやりゃいいんだ?

たしかに、10進数みたくA=A+1みたいに書くわけにはいかないよね。第2ビットを1にするには、ええと……

フラグを立てるならビット演算の
ORを使うのがキホンかな。
たとえばまっさらな変数
Aがあったとしよう。
A=0だから、2進数でも
0000なのはわかるよね。
この3ケタ目(第2ビット)を立てるには、こうするよ。
0000
OR 0100
= 0100
ここで
ORに使った
0100は、10進数で言いかえれば4。
つまり、
A=A OR 4と書けば、第2ビットが立つことになるね。

ORを使うのはワカッたが、イチイチ10進数に直すのがカッタルイぜ!

なれないウチは並んだ2進数の右ハジから、「1、2、4、8、……」と倍にしながら数えていくのがカンタンかもしれんな。10進数で右ハジから「一、十、百、千、万、……」とケタを数えるノリでいけるぞい。

第2ビットが立っているときに、もういちど
OR 4すると……
0100
OR 0100
= 0100
やっぱりそのままだね。
ORはビットを立てるために使うってコトか。

オン・オフを逆にしたい時は、
XORがオススメだね。
ためしに
1100と
1000、どっちにも
0100で
XORしてみるよ。
1100 1000
XOR 0100 XOR 0100
= 1000 = 1100
1で
XORした第2ビットだけがひっくり返って、ホカのケタはそのまま残るのがわかるだろう。

XORって使い方がムズカシいと思ってたけど、こういう時にベンリなんだね。

じゃあ、とにかく0にしたいってトキは……そうか、
ANDだな?
0100 1111
AND 1011 AND 1011
= 0000 = 1011
1011で
AND、10進数で言えば
AND 11だな。
これでホカのケタはそのままで、第2ビットだけが0になったぜ!

なかなかワカッてきたではないか。
さっきの復習じゃが、
ANDを使ったフラグチェックには、こういうテクニックもあるのう。
1110
AND 0100
= 0100
AND 4すると、第2ビット以外はゼロになったじゃろう。

BUTTON()で使ったテクだな! 第2ビット以外をゼロにすれば、第2ビットのオン・オフだけがハッキリする。ツマリ……エー……

そうか! そうなると、IF A THENの形が使えるんだね。

そのトオリ。1行にまとめると、IF A AND 4 THEN~だね。
もちろんホカにもA=A AND 4:IF A==FALSE THEN~ なんかでもいいけど、とにかく決まったケタのナカミだけがスグにわかるよね。

ホカのケタがまるまるゼロになっちまうが……、ああ、そこは変数のナカミをあらかじめコピーしとけばいいのか?

そうじゃな、A=Bとか逃がしてから、B=B AND 4などとするのがアンゼンじゃろうの。

まだまだイロイロなテクニックはあるよ。なかなかオクの深い世界だろう。

とっつきはワルいが、使いミチはワカッてきた気がするぜ。てコトは、このアトすぐに使う場面があるワケだな?

いや、そうともかぎらんが。

えー……?
- ループする数
- A=(A+1) AND 3
こう書くと、A=0から始めて、この式を3+1回くり返したとき、変数Aは0に戻ります。
3以外に、7、15、31、63……と、「2のべき乗」マイナス1の数で同じパターンが使えます。
- ビット演算を使ったフラグ
- たとえば2進数の0000(10進数の0)を「4つ並んだフラグ」と見なせば、4種類のオン・オフを管理できます。
0001(10進数の1)なら「第0ビットが立った」状態、0100(10進数の4)なら「第2ビットが立った」状態と言えます。
他のケタを変化させずに第2ビットだけを1にしたければOR 4(2進数の0100)、第2ビットだけを0にしたければAND 11(2進数の1011)することになるでしょう。
第2ビットの状態だけを反転させるには、XOR 4(2進数の0100)がいいでしょう。
わざとAND 4(2進数の0100)することで、第2ビット以外を0にして、第2ビットの状態をハッキリさせる方法もあります。
こういったあるひとケタだけが1になっている数は、10進数に直せば「1、2、4、8……」と倍々に増えていく数になります。