せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】【アルゴリズム】ビットカウント。最下位の1を倒していくVer。ループしないVer。

このサイトを参考に、
ビット演算の奥深さを勉強中。
 

レジスタ中の 1 になっているビット数を数えるアルゴリズム

 

最下位の1を倒していく

def numofbits3 bits
	num = 0
	while bits != 0 do
		num += 1 if (bits & (bits-1))
		bits = bits & (bits-1)
	end
	num
end
p numofbits3(0b100000000000000000000000000000000000000000001)

■実行結果

2

 
なるほど。
「bits & (bits-1)」 は最下位の1をOFFにする働きがある。
いわれてみたら確かに。

 

ループを使わないVer

ビットを数える最適化されたアルゴリズム。
int numofbits5(long bits)
{
bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555);
bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333);
bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f);
bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff);
return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff);
}

 
この数値は何を意味してるんだろう?

p 0x55555555.to_s(2)
p 0x33333333.to_s(2)
p 0x0f0f0f0f.to_s(2)
p 0x00ff00ff.to_s(2)
p 0x0000ffff.to_s(2)

 
■実行結果(整形しています)

"101_0101_0101_0101_0101_0101_0101_0101"
"11_0011_0011_0011_0011_0011_0011_0011"
"1111_0000_1111_0000_1111_0000_1111"
"1111_1111_0000_0000_1111_1111"
"1111_1111_1111_1111"

ふむ。。
 
以下のサイトを参考に理解しました。
http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html#Q3http://tak5219.seesaa.net/article/7042181.html

なるほど。。
これは32ビットが上限だけど、

たとえば64ビットまで計算可能にするならばこうなる↓
もちろん左シフトで32ビットづつ減らしていってloopすることはできるけど。

target =Array.new(26,0)
target += Array.new(36,1)
value = target.shuffle!.join("")
bits = value.to_i(2)
    bits = (bits & 0x5555555555555555) + (bits >> 1 & 0x5555555555555555);
    bits = (bits & 0x3333333333333333) + (bits >> 2 & 0x3333333333333333);
    bits = (bits & 0x0f0f0f0f0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f0f0f0f0f);
    bits = (bits & 0x00ff00ff00ff00ff) + (bits >> 8 & 0x00ff00ff00ff00ff);
    bits = (bits & 0x0000ffff0000ffff) + (bits >>16 & 0x0000ffff0000ffff);
    bits = (bits & 0x00000000ffffffff) + (bits >>32 & 0x00000000ffffffff);
p bits

■実行結果

36

徐々に寄せるのか。。すごいな。