BeInteractive!

馬鹿全さんが FLASHer 向けビット演算入門記事をアップしてますね。AS3 においては、必ずしも高速化にはつながらないですが、ビット演算ってパズルみたいで面白いですよね。例えば、

n = Math.max(n, 255);

※ n は整数 (uint)

の代わりに、

n = (n | (((n & 0xffffff00) + 0x7fffffff) >> 31)) & 0xff;

とか!

何をやってるのか少しずつ見て行ってみましょう。

一番最初に実行されるのは n & 0xffffff00 です。これで、「n が 255 以下の場合には 0 、それ以外は 1 以上」な値が作れます。

なぜかというと、255 以下の値というのは、8 ビットで全て表現出来るため、上位 24 ビットは必ず全て 0 になります。逆に 255 より大きい値は 9 ビット以上必要で、必ず上位 24 ビットのうち最低でもひとつは 1 のビットがあります。ここで、0xffffff00 (2 進数で書くと

1111 1111 1111 1111 1111 1111 0000 0000

となる) との論理積をとると、その上位 24 ビットの値のみが反映され、255 以下の場合は 0、255 より大きい場合は 1 以上となります。

例えば 57 は

   0000 0000 0000 0000 0000 0000 0011 1001 ← 57
&) 1111 1111 1111 1111 1111 1111 0000 0000 ← 0xffffff00
------------------------------------------
   0000 0000 0000 0000 0000 0000 0000 0000

で 0 となり、308 は

   0000 0000 0000 0000 0000 0001 0011 0100 ← 308
&) 1111 1111 1111 1111 1111 1111 0000 0000 ← 0xffffff00
------------------------------------------
   0000 0000 0000 0000 0000 0001 0000 0000

で、1 以上の値となります。

続いて、+ 0x7fffffff です。0x7fffffff は、

0111 1111 1111 1111 1111 1111 1111 1111

というように、最上位ビットのみ 0 な値で、ここに 1 以上の値を足せば、繰り上がりによって、最上位ビットを 1 にすることができます。前の段階で 255 以下で 0、255 より大きいと 1 以上な値を作ったので、これにより、255 以下であれば最上ビットが 0、255 より大きいと最上位ビットが 1 な値を作ることができます。

57 の例の続きで言うと、

   0000 0000 0000 0000 0000 0000 0000 0000 ← 前段階で作った値
+) 0111 1111 1111 1111 1111 1111 1111 1111 ← 0x7fffffff
------------------------------------------
   0111 1111 1111 1111 1111 1111 1111 1111

で最上位ビットが 0、308 の例の続きだと

   0000 0000 0000 0000 0000 0001 0000 0000 ← 前段階で作った値
+) 0111 1111 1111 1111 1111 1111 1111 1111 ← 0x7fffffff
------------------------------------------
   1000 0000 0000 0000 0000 0000 1111 1111

で、最上位ビットが 1 になります。

続いて、>> 31 による符号付き右ビットシフトです。符号付きビットシフトというのは便利で、ビットシフトしたビット数だけ、上位ビットが、最上位ビットの値で埋められる性質があります。これを利用して、31 ビット右にシフトすると、全ビットを最上位ビットの値に変えることができます。

57 の例の続きで言うと、

   0111 1111 1111 1111 1111 1111 1111 1111 ← 前段階で作った値
>> 32)
------------------------------------------
   0000 0000 0000 0000 0000 0000 0000 0000

で、全ビットが 0、308 の例の続きだと

   1000 0000 0000 0000 0000 0000 1111 1111 ← 前段階で作った値
>> 32)
------------------------------------------
   1111 1111 1111 1111 1111 1111 1111 1111

で、全ビットが 1 になります。

さて、長々とやってきましたが、これで何が出来たかおさらいすると、n が 255 以下の場合は全ビットが 0、n が 255 より大きい場合は全ビットが 1 な値が作れたということです。ここまでくれば後もう一歩です。

次に、その値と、n の論理和をとります。すると、n が 255 以下の場合は n、n が 255 より大きい場合は 0xffffffff (全ビットが 1) になります。

57 の例の続きで言うと、

   0000 0000 0000 0000 0000 0000 0000 0000 ← 前段階で作った値
|) 0000 0000 0000 0000 0000 0000 0011 1001 ← n つまり 57
------------------------------------------
   0000 0000 0000 0000 0000 0000 0011 1001

で 57 のまま、308 の例の続きで言うと

   1111 1111 1111 1111 1111 1111 1111 1111 ← 前段階で作った値
|) 0000 0000 0000 0000 0000 0001 0011 0100 ← n つまり 308
------------------------------------------
   1111 1111 1111 1111 1111 1111 1111 1111

で 0xffffffff (全ビットが 1) になります。

最後に、0xff との論理積をとると、57 の例の場合は

   0000 0000 0000 0000 0000 0000 0011 1001 ← 前段階で作った値
|) 0000 0000 0000 0000 0000 0000 1111 1111 ← 0xff
------------------------------------------
   0000 0000 0000 0000 0000 0000 0011 1001 ← 57

で、変わらず 57、しかし 308 の例の場合は

   1111 1111 1111 1111 1111 1111 1111 1111 ← 前段階で作った値
|) 0000 0000 0000 0000 0000 0000 1111 1111 ← 0xff
------------------------------------------
   0000 0000 0000 0000 0000 0000 1111 1111 ← 255

で、255 に収まります。めでたしめでたし!

…なんか、解説しようと思ったら思ったより言葉で説明するの大変でした。ぜひ他の値だとどうなるか手を動かして試してみてください。

この記事へのトラックバック

ビット演算(ビットえんざん)とは、 ひとつあるいはふたつのビットパターンまたは二進数を個々のビットの列として操作することである。 CPUからすればビット演算は簡単...

TrackBack URL:

http://www.be-interactive.org/trackback.php?id=519

この記事へのコメント

霜月 wrote:
n = Math.min(n, 255)だよね?

コメント書き込み:

カテゴリ

タグ

アーカイブ