大量の、互いに独立なビットフラグをチェックし、 それぞれフラグが立っていたら(あるいは立っていなかったら) ある特定の処理を行う、 というコードを書くことはよくある。
「イベントループ」と言われるものの一番コアなループは、 結局このように作られている。 たとえば「シフトキーを押しながらマウスをクリック」 などという状態を表現するには、 シフトキー、マウスのクリックのそれぞれに対してビットを割り当て、 その状態を監視して、 必要な組み合わせに対してコールするべき関数を決定するわけだ。
当然、この場合問題になるのが、 どうやって「どの1ビットが立っているのか」を高速に検出するかである。
例えば 16 種類のイベントがあるなら、 このイベントフラグは全部で 16 bit のはずなので、 大抵の場合どのイベントが成立しているのかを調べる「フラグチェック」は
for ( i = 0; i < 16; i++ ) { event = flag & ( 1 << i ); switch ( event ) { case HOGE: .... break; case HAGE: .... break; ..... default:break; } }のようなプログラムで実装されることになる。 しかし、これだとイベントがたった1つでも16個のフラグ全部を 丁寧に見て回ることになる。 イベントの数が増え、かつその発生率が低い場合、 これは効率が悪い。
ある整数のレジスター x の最も低位のビットを返す技法がある。
この技法を応用すると、この「フラグチェック」ルーチンは次のようになる。
while ( flag ) { event = flag & (( ~flag ) + 1 ); flag ^= event; switch( event ) { ..... } }このコードの場合、 ループ回数は純粋に 1 が立っているフラグの数だけ、 つまりイベントの数だけに制限される。 ちなみに switch 文の中身は、 binary tree を用いる方法である程度高速化は可能だが、 圧倒的に有利な方法は見つかっていない。
ちなみにこの逆、
つまり単純な算術演算と論理演算だけを用いて
MSB に最も近いビットのみを 1 にする方法は見つかっていない。
このためと、switch() 文高速化のために、
「MSB に最も近いビットの bit id を返す命令」
を備えた CPU は存在する(PowerPC もその一つだ)。