web-dev-qa-db-ja.com

O(1)でのハミング重みの計算

バイナリ表現では、ハミング重みは1の数です。私はウェブに出会い、O(1)答えを見つけました:

v = v - ((v>>1) & 0x55555555);
v = (v & 0x33333333) + ((v>>2) & 0x33333333);
int count = ((v + (v>>4) & 0xF0F0F0F) * 0x1010101) >> 24;

しかし、私はアルゴリズムを完全に理解しておらず、どこにでもその説明を見つけることができません。誰かがそれを特に最後の行について少し説明してもらえますか?

22
NSF

これは、「母集団」関数と呼ばれる、ビットをカウントするための分割統治戦略の一部です。この戦略の学術的扱いは、Reingold and Nievergelt、1977に記載されています。

アイデアは、最初にビットをペアごとに合計し、次に4ごとに合計し、次に8ごとに合計する、などです。たとえば、ビット1011がある場合、最初のペア10は、1つのビットがあるため01になり、2番目のペアは、10がバイナリであり、10 = 2に2つのビットがあるため、11になります。ここでの重要な事実は次のとおりです。

population(x) = x - (x/2) - (x/4) - (x/8) - (x/16) - ... etc.

正確なアルゴリズムは、「HAKMEM」アルゴリズムとして知られているものの変形です(Beeler、Gosper and Schroppel、1972を参照)。このアルゴリズムは、4ビットフィールドの1を並列でカウントし、これらの合計が8ビットの合計に変換されます。最後のステップは、0x01010101を乗算してこれらの4バイトを追加する操作です。 0x0F0F0F0Fマスクは、非合計情報をマスクして、4バイトのバイト合計を取得します。たとえば、8桁のフィールドが10110110であるとすると、0101と等しい5ビットがあるため、10110101になります。重要なのは最後の4ビットだけなので、最初の4ビットを除外します。

10110101 & 0x0F = 00000101

ヘンリーウォーレンの本「Hacker's Delight」には、ビットを数える細かい点に関する章全体が記載されています。

25
Tyler Durden