探しているのは「popcount」です。これは、後のx64 CPUに単一のCPU命令として実装されており、速度に勝るものはありません。
#ifdef __APPLE__
#define NAME(name) _##name
#else
#define NAME(name) name
#endif
/*
* Count the number of bits set in the bitboard.
*
* %rdi: bb
*/
.globl NAME(cpuPopcount);
NAME(cpuPopcount):
popcnt %rdi, %rax
ret
ただし、もちろん、最初にCPUがサポートしていることをテストする必要があります。
/*
* Test if the CPU has the popcnt instruction.
*/
.globl NAME(cpuHasPopcount);
NAME(cpuHasPopcount):
pushq %rbx
movl $1, %eax
cpuid // ecx=feature info 1, edx=feature info 2
xorl %eax, %eax
testl $1 << 23, %ecx
jz 1f
movl $1, %eax
1:
popq %rbx
ret
Cでの実装は次のとおりです。
unsigned cppPopcount(unsigned bb)
{
#define C55 0x5555555555555555ULL
#define C33 0x3333333333333333ULL
#define C0F 0x0f0f0f0f0f0f0f0fULL
#define C01 0x0101010101010101ULL
bb -= (bb >> 1) & C55; // put count of each 2 bits into those 2 bits
bb = (bb & C33) + ((bb >> 2) & C33);// put count of each 4 bits into those 4 bits
bb = (bb + (bb >> 4)) & C0F; // put count of each 8 bits into those 8 bits
return (bb * C01) >> 56; // returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
GNU Cコンパイラランタイムには、上記の実装よりも高速な「組み込み」が含まれています(CPU popcnt命令を使用する場合がありますが、これは実装固有です)。
unsigned builtinPopcount(unsigned bb)
{
return __builtin_popcountll(bb);
}
ビットボードを使用して駒の位置を表す場合、ポップカウントがチェスの動きの生成に重要な役割を果たすため、上記のすべての実装がC++チェスライブラリで使用されます。ライブラリの初期化中に設定された関数ポインターを使用して、ユーザーが要求した実装をポイントし、そのポインターを介してpopcount関数を使用します。
興味深い問題であるため、Googleは他の多くの実装を提供します。例:http ://wiki.cs.pdx.edu/forge/popcount.html 。