論理演算(&|^)はどこで使う?



 論理演算の1つに論理積というのがあります。多くの場合ANDまたは&といった命令/記号で表されます。JavaScriptの場合は&です。ところで、この&(論理積)いつ、どこで使うのでしょうか? 結構いろいろ使えるのですが、まずアニメです。GIFアニメは簡単に再生してくれますがJPEGアニメは存在しないのでJavaScriptで作成することになります。さて、ここでアニメーションさせる画像の枚数は、何枚にすればプログラム作成時に便利かつ素早い動作が行われるでしょうか?

 正解は2のn乗です。つまり2, 4, 8, 16, 32, 64, 128, 256, 512...となります。とりあえずここでは8枚のJPEGアニメーションを考えてみましょう。&(論理積)を使わない場合の実際のプログラムは以下のようになります。Num画像の番号になります。使用する画像は「0.jpg」「1.jpg」...「7.jpg」になっています。

Num = 0
function JPEG_ANIME(){
document.myIMG.src = Num +".jpg"
Num = Num + 1
if (Num > 7) Num = 0
}


 このような場合、普通の方法では7より大きくなったかどうかを判定するためのif文が必要です。この部分に&(論理積)を使うと以下のようなプログラムになります。

Num = 0
function JPEG_ANIME(){
document.myIMG.src = Num +".jpg"
Num = (Num + 1) & 7
}

 これでも正しく動作します。if文がなくなったので、さらに短く記述する事もできます。

 ++と&をうまく組み合わせると以下のように3行あったプログラムがわずか1行になります。注意して欲しいのは短くなったからといって万事うまくいくわけではありません。特に他人と共同で使用する場合や保守メンテナンスを重視する場合は逆にわかりにくいものになってしまう恐れがあるからです。速度/サイズ優先か、保守性を重視するかは製作者の判断によります。

Num = 0
function JPEG_ANIME(){
document.myIMG.src = ((Num++) & 7) +".jpg"
}

 &(論理積)を使うと短くでき、期待通りの動作をするのはわかりましたが、なぜ動作するのでしょうか。それには&(論理積)がどのような原理で処理されるか知っておく必要があります。&(論理積)は「ビット演算」を行う命令です。+や-など四則演算を行うものと異なり値をビット単位に分解して演算するのが論理演算です。論理演算には「論理積」「論理和」「排他的論理和」があります。JavaScriptでは、それぞれ以下のように記号と対応しています。

論理積
&
論理和
|
排他的論理和
^


 論理積は2つの値の対応するビットが1の時に1になり、それ以外は0になります。実際の例を見てみましょう。13と7の論理積をとってみます。まず、それぞれビット列に分解します。

13
1101
7
0111
5
0101

結果は5となります。7と論理積をとると右側の3つのビットしか1でないため絶対に7より演算結果が大きくなることはないのです。

 それでは他の論理演算も見てみましょう。ここでは論理積もまとめて載せてあります。

   論理積:2つのビットが1の時1。それ以外は0。
   論理和:2つのビットが0の時0。それ以外は1。
排他的論理和:2つのビットが異なる時1。同じ時は0。

例:左側の数字は10進数。その10進数をビットで表したものが右側の太字。
名称
論理積
論理和
排他的論理和

13:1101
13:1101
13:1101

7:0111
7:0111
7:0111
演算結果
5:0101
15:1111
12:1010


 それでは次に「論理和」の使い道を見てみましょう。

 論理和は常に値を奇数にしたい場合や仮想キー入力処理、複数の値を1つに連結/まとめる場合に使います。論理和はどちらかの値の対応するビットが1なら1になりますから、Numという変数の値を常に奇数にするには以下のようになります。

Num = Num | 1(またはNum =| 1)

 仮想キー入力処理はmodifierなど修飾キー情報はビット列で返されます。常にSHIFTキーをONの状態にしておきたいならば以下のようにします。(NS4.x, theEventはEventオブジェクト, 4はShiftキーのビット値)

mKey = theEvent.modifiers | 4

 次に「排他的論理和」の使い道です。排他的論理和はトグルスイッチ、つまり1と0が切り替わるような場合に使います。画像を点滅させる場合などは「画像オン」「画像オフ」の繰り返しになります。点滅させるかどうかのフラグ変数がflagならば以下のようになります。

flag = flag ^ 1(またはflag ^= 1)

ビット列に分解してみると動作がわかります。(1)と(2)の繰り返しになるのがわかるでしょうか。


1回目 2回目
flagの値
0: 0000
1: 0001

1: 0001
1: 0001
結果
1: 0001
0: 0000


 画像のアニメーションを行うには2のn乗の枚数にしておけば便利だというのは先にも書きました。が実際には、そううまくいかない場合があります。画像の枚数が13枚とか27枚などなど。このような場合はif文を使わなければいけないのか?というとそうでもありません。このような不特定枚数の場合は「剰余」(割り算の余り)を使うのです。JavaScriptでは剰余は%となっています。先の8枚のアニメーションの場合は以下のようになります。13枚ならば8の部分を13、27枚ならば8の部分を27にすればよいのです。

Num = 1
function JPEG_ANIME(){
document.myIMG.src = ((Num++) % 8) +".jpg"
}

 最後にビットについて説明しておきます。ビットは0または1のどちらかの値を示します。しかし、これでは2や128など大きな数値を表すことができません。そこでビットを並べてそれぞれに「重み」をもたせます。コンピューターでは2のn乗の重みを持たせています。以下の4ビットの重みは以下のようになります。

(ビット列)1 1 1 1
  (重み)8:4:2:1

1ならば重みを加算、0なら加算しないという具合です。例えば13であれば8+4+1=13ですから以下のようになります。

(ビット列)1 1 0 1
  (重み)8:4:2:1
---------------------
      8+4+0+1 = 13