种群计数 (pop_count)

//高效程序的奥秘hacker's delight Henry S. Warren, Jr. 著冯速译

//5 章位计数5.1 1 位计数

// 应用:

//     Hamming 距离是矢量间取不同值的对应位的数目,dist(x, y) = pop(x ^ y);

//   稀疏数组A 压缩后的简便访问方式,可以利用位串数组BITS 记录相应下标有定义的元素,

// 如每个有定义的A[i]BITS 的第I 个元素是1 位。

 

#include "iostream"

#include "bitset"

#include "limits"

#include "time.h"

 

using namespace std;

 

#define out2(T) cout<<bitset<numeric_limits<unsigned int>::digits>(T)<<endl;

#define SIZE(T) (numeric_limits<unsigned T>::digits)

 

bool SHR31(int x)           //逻辑右移位

{

     return (unsigned int)x>>31;

}

 

#define HOUT(x,y,z)    hex_out(x,y,z)

 

inline void hex(int x)

{

     int w = cout.width();

     cout << "0x";

     cout.width(8); cout.fill('0');

     cout << hex << x << "  ";

     cout.width(w);

}

inline void hex(unsigned __int64 x)

{

     int w = cout.width();

     cout << "0x";

     cout.width(16); cout.fill('0');

     printf("%I64x   ",x);

     cout.width(w);

}

void hex_out(int x, int y, int z)

{

     hex(x); hex(y); hex(z); cout << endl;

}

 

// 循环左移位

int rotate(unsigned int x, int n)

{

     return   (x<<n) | (x >> (32-n));

}

 

// 统计x 中位1 的个数

// 首先设置每个2 位字段为原来的两个单位的和,然后,求相邻位字段的和,把结果放入相应的位字段,以此类推。

int pop(unsigned int x)

{

     x = (x & 0x55555555) + ((x >> 1) & 0x55555555);

     x = (x & 0x33333333) + ((x >> 2) & 0x33333333);

     x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);

     x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);

     x = (x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF);

     return x;

}

 

// x 的第一个赋值基于下面这个相当巧妙的公式的前两项

// pop(x) = x - floor(x/2) - floor(x/4) - ... - floor(x/2^31);

// 设字是b3b2b1b0

// bi = floor(x/2^i) - 2*floor(x/2^(i+1))

int pop2(unsigned int x)

{

     x = x - ((x >> 1) & 0x55555555);

     x = (x & 0x33333333) + ((x >> 2) & 0x33333333);

     x = (x + (x >> 4)) & 0x0F0F0F0F;

     x = x + (x >> 8);

     x = x + (x >>16);

     return x & 0x00000003F;

}

 

// [HAK, item169]

// http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html

// DEC PDP-10计算机上只需要10 个指令

// 它是十进制计数的计算机,mod 63 很方便

// 注意:以0 开头的数是八进制数

// 前三项萃取位字段的数目

// 举例:如每三位字段全 111B

// (1): 取出高二位对应1 的值, 有两个1 ,则取出后n 011

// (3): 取出最高位对应1 的值,有一个1 ,则取出后n 001

// (2),(4): x - n - n , 刚好11X - 011 - 001 2+X =高二位1 的数目+X

// 而最低位X 1 则自然加1,为0 自然加0

// (5): 合并相邻的两个三位字段成六位字段

// (6): mod 63 是怎么操作的呢?

// 假设六位字段值为a6 a5 a4 a3 a2 a1 a0

// 十进制和为a6*64^5 + a5*64^4 + ... + a0

// = a6* (63+1)^5 + a5* (63+1)^4 + ... + a0

// mod 63 刚好剩下a6 + a5 + ... + a0

// 从而把所有六位字段相加,统计1 的总和

int pop3(unsigned int x)

{

#define modu(x, y) (x % 63)

     unsigned int n;

     n = (x >> 1) & 033333333333;

     x = x - n;

     n = (n >> 1) & 033333333333;

     x = x - n;

     x = (x + (x >> 3)) & 030707070707;

     x = modu(x, 63);

     return x;

}

 

int pop4(unsigned int x)

{

     unsigned int n;

 

     n = (x >> 1) & 0x77777777;

     x = x - n;

     n = (n >> 1) & 0x77777777;

     x = x - n;

     n = (n >> 1) & 0x77777777;

     x = x - n;

     x = (x + (x >> 4)) & 0x0F0F0F0F;

     x = x * 0x01010101;

     return x >> 24;

}

 

int pop5(unsigned int x)

{

     int n;

 

     n = 0;

     while (x != 0) {

         n += 1;

         x = x & (x - 1); // 把最右侧的1 位改成0

     }

     return n;

}

 

int pop6(unsigned int x) {

     int i, sum;

 

     sum = x;

     for (i = 1; i <= 31; i++) {

         x = rotate(x, 1);

         sum += x;

     }

     return -sum;

}

 

 

// 只计算七位量

int pop7(unsigned int x) {

     x = x * 0x02040810;

     x = x & 0x11111111;

     x = x * 0x11111111;

     x = x >> 28;

     return x;

}

 

// 只计算八位量

int pop8(unsigned int x) {

     x = x * 0x08040201;

     x = x >> 3;

     x = x & 0x11111111;

     x = x * 0x11111111;

     x = x >> 28;

     return x;

}

 

int pop9(unsigned int x) {

     int sum;

 

     sum = x;

     while (x != 0) {

         x = x >> 1;

         sum = sum - x;

     }

     return sum;

}

 

// table 存放0 255 x 的所有pop(x)

int pop10(unsigned int x) {

     static char table[256] = {

         0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,

         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,

         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,

         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,  

         1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,

         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 

         2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 

         3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8

     };

    

     return table[x           & 0xFF] +

            table[(x >> 8) & 0xFF] +

            table[(x >>16) & 0xFF] +

            table[(x >>24)];

}

 

//GNU c 的无符号long long

/*

int pop64(unsigned int x) {

     unsigned long long y;

     y = x * 0x0002000400080010ULL;

     y = y & 0x1111111111111111ULL;

     y = y * 0x1111111111111111ULL;

     y = y >> 60;

     return y;

}

*/

 

// 15 位量算术版本

const unsigned __int64 a = 0x0002000400080010;

const unsigned __int64 b = 0x1111111111111111;

int pop15(short x) {

     unsigned __int64 y;

     y = x * a;

     y = y & b;

     y = y * b;

     y = y >> 60;

     return y;

}

 

// 生成一个包含4 8 位部分和的字。然后,尽可能把这些字加起来后,生成一个全字和。

// 相加不会产生溢出的8 位字段的字的数目是floor(255/8) = 31

int pop_array(unsigned int A[], int n) {

     int i, j, lim;

     unsigned int s, s8, x;

 

     s = 0;

     for (i = 0; i < n; i += 31) {

         lim = __min(n, i + 31);

         s8 = 0;

         for (j = i; j < lim; j++) {

              x = A[j];

              x = x - ((x >> 1) & 0x55555555);

              x = (x & 0x33333333) + ((x >> 2) & 0x33333333);

              x = (x + (x >> 4)) & 0x0F0F0F0F;

              s8 = s8 + x;

         }

         x = (s8 & 0x00FF00FF) + ((s8 >> 8) & 0x00FF00FF);

         x = (x & 0x0000FFFF) + (x >> 16);

         s = s + x;

     }

     return s;

}

 

void test5();

void main()

{

     test5();

}

 

 

void test5()

{

     srand((unsigned)time(NULL));

     unsigned int a[256] = {0}; int i;

 

     for (i = 0; i < 256; i++) {a[i] = i;}

     cout << pop_array(a, 256) << endl;

 

     for (i = 0; i < 256; i++) {a[i] = 1;}

     cout << pop_array(a, 256) << endl;

 

     for (i = 0; i < 256; i++) {a[i] = 0;}

     cout << pop_array(a, 256) << endl;

 

     for (i = 0; i < 256; i++) {a[i] = -1;}

     cout << pop_array(a, 256) << endl;

 

     for (i = 0; i < 256; i++) {a[i] = rand()%256;}

     cout << pop_array(a, 256) << endl;

}

void test4()

{

     short x;

 

     x = 0x7FFF; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x0001; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x4000; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x5555; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x2AAA; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x3333; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x2CCC; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x7FFF; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x5B93; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x2C64; hex(x); cout<< dec << pop15(x) << endl;

 

     x = 0x8000; hex(x); cout<< dec << pop15(x) << endl;

 

}

void test3()

{

     unsigned char x;

 

     x = 0x7F; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0xFF; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0x0; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0xAC; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0x80; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0xBD; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0x55; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0xAA; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0x0F; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0xF0; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0xE4; hex(x); cout<< dec << pop8(x) << endl;

 

     x = 0x110; hex(0x110); cout << dec << pop7(x) << endl;

}

void test2()

{

     char x;

 

     x= 0x7F; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x0; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x0F; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x70; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x55; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x2A; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x5D; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0x33; hex(x); cout << dec << pop7(x) << endl;

 

     x= 0xF0; hex(x); cout << dec << pop7(x) << endl;

}

void test1()

{

     int x;

 

     x = 0x7FFFFFFF; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0; hex(x); cout<< dec << pop6(x) << endl;

 

     x = -1; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 1; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0xABCDE123; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0x87654321; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0x55555555; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0x80808080; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0xABC5DEFA; hex(x); cout<< dec << pop6(x) << endl;

 

     x = 0X80000000; hex(x); cout<< dec << pop6(x) << endl;

}

 

 

你可能感兴趣的:(c,table,null,BI,iostream,hex)