バイナリ表現では、ハミング重みは1の数です。私はウェブに出会い、O(1)答えを見つけました:
v = v - ((v>>1) & 0x55555555);
v = (v & 0x33333333) + ((v>>2) & 0x33333333);
int count = ((v + (v>>4) & 0xF0F0F0F) * 0x1010101) >> 24;
しかし、私はアルゴリズムを完全に理解しておらず、どこにでもその説明を見つけることができません。誰かがそれを特に最後の行について少し説明してもらえますか?
これは、「母集団」関数と呼ばれる、ビットをカウントするための分割統治戦略の一部です。この戦略の学術的扱いは、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」には、ビットを数える細かい点に関する章全体が記載されています。