# (转)位计算的诸多算法（计算二进制1的个数）

#### 位计算（Bit Count）

1.循环

Iterated Count

public int bitCount_Iterated(long n){
int count = 0;
while(n != 0){
count += (int)(n & 0x1L);
n >>= 1;
}
return count ;
}

Sparse Count

public int bitCount_Sparse(long n){
int count = 0;
while(n != 0){
count ++;
n &= (n - 1);
}
return count ;
}

Dense Count

public int bitCount_Dense(long n){
int count = 64;
n = ~n;
while(n != 0){
count --;
n &= (n - 1);
}
return count ;
}

2.查表

private int[] BIT_COUNT_TABLE_8;
private int[] BIT_COUNT_TABLE_16;
public void GenerateBitCountTable(boolean bits8){
int size, length, bits, count;
int[] table;
if(bits8){
BIT_COUNT_TABLE_8 = new int[1 << 8];
table = BIT_COUNT_TABLE_8;
size = 1 << 8;
length = 8;
}else{
BIT_COUNT_TABLE_16 = new int[1 << 16];
table = BIT_COUNT_TABLE_16;
size = 1 << 16;
length = 16;
}

for(int i = 0; i < size; i++){
bits = i;
count = 0;
for(int j = 0; j < length; j++){
if(((bits >>> j) & 1) != 0)
count++;
}
table[i] = count;
}
}

Precompute 8bits Count

public int bitCount_Precomput8(long n){
int[] table = BIT_COUNT_TABLE_8;
return table[(int)(n & 0xffL)]

+ table[(int)((n >> 8) & 0xffL)]

+ table[(int)((n >>> 16) & 0xffL)]

+ table[(int)((n >>> 24) & 0xffL)]

+ table[(int)((n >>> 32) & 0xffL)]

+ table[(int)((n >>> 40) & 0xffL)]

+ table[(int)((n >>> 48) & 0xffL)]

+ table[(int)((n >>> 56) & 0xffL)];

}

Precompute 16bits Count

public int bitCount_Precomput16(long n){
int[] table = BIT_COUNT_TABLE_16;
return table[(int)(n & 0xffffL)]

+ table[(int)((n >>> 16) & 0xffffL)]

+ table[(int)((n >>> 32) & 0xffffL)]

+ table[(int)((n >>> 48) & 0xffffL)];
}

3. 平行算法

private final long MASK_1 = 0x5555555555555555L;
private final long MASK_2 = 0x3333333333333333L;
private final long MASK_4 = 0x0F0F0F0F0F0F0F0FL;
private final long MASK_8 = 0x00FF00FF00FF00FFL;
private final long MASK_16 = 0x0000FFFF0000FFFFL;
private final long MASK_32 = 0x00000000FFFFFFFFL;

Parallel Count
public int bitCount_Parallel(long n){
return (int)n;
}

Nifty Count

public int bitCount_Nifty(long n){
n = (n & MASK_1) + ((n >>> 1) & MASK_1) ;
n = (n & MASK_2) + ((n >>> 2) & MASK_2) ;
n = (n & MASK_4) + ((n >>> 4) & MASK_4) ;
return (int)(n % 255L);
}

MIT HACKMEM Count

public static int bitCount_MIT(long n) {
// HD, Figure 5-14
n = n - ((n >>> 1) & 0x5555555555555555L);
n = (n & 0x3333333333333333L) + ((n >>> 2) & 0x3333333333333333L);
n = (n + (n >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
n = n + (n >>> 8);
n = n + (n >>> 16);
n = n + (n >>> 32);
return (int)n & 0x7f;
}

Neat Count

private final long SHIFT_256   = 0x0101010101010101L;

public int bitCount_Neat(long n){
n = n - ((n >>> 1) & MASK_1);
n = (n + (n >>> 4)) & MASK_4;
return (int)((n * SHIFT_256) >>> 56);
}

/* MCPS = Million counts per second     Total Count = 100 million

Loop Time(ms)            Compute time(ms)
*                                  Loop time    Compute time   MCPS
*bitCount_Neat               469                2249             44
*bitCount_MIT                484                2844             35
*bitCount_Nifty               469                5797            17
*bitCount_Parallel           468                3579            27
*bitCount_Precomput16  453               1531            65
*bitCount_Precomput8    469               2781            35
*bitCount_Dense              469              31109           3
*bitCount_Sparse            485               9718            10
*bitCount_Iterated          469              13031           7*/

bitCount_Dense 的效率在平均情况下，应该和bitCount_Sparse相当，在此可能是因为我的测试数据是从0－100000000之间的缘故，100000000＝5F5E100 也就用了28位。从表中可以看出，16位查表的方法是最快，但是需要64k的空间来存储查询的表。另外比较bitCount_Neat和bitCount_Nifty ，可以看出％操作的开销是很大的。bitCount_Neat和bitCount_MIT比较，可以看出乘法操作的开销不是很大。

posted @ 2010-10-22 22:26  elite_lcf  阅读(1472)  评论(0编辑  收藏  举报