Bit算法
将一些运算在位上进行操作,可以加快操作的速度,本博文将使用Bit算法实现符号函数、保留bit串最高位的1、保留bit串最低位的1、计算bit串的前导0、计算bit串中的1的数量、反转bit串。这些操作都是在32bit的计算机上运行。
1.符号函数实现:对于任意的整数x,若x<0,要得到x的符号,只需将x进行不带符号右移31位即可得到x的符号,一般地计算机进行位移一般都是这种操作;若x>0,需要将x变成带符号右移31位即可得到x的符号;
若x=0,则以上两种操作的结果都一样,均为0,相应的代码实现如下:
int sign(int x) {//使用bit算法实现符号函数 int i = (x >> 31) | ((unsigned int)-x >> 31); return i; }
以上代码将三种情况用一条表达式表示,需要注意的是,负数不带符号进行右移补充的是符号位1,知道这点理解以上表达式就很容易了。
2.保留最高位的1:操作的思路是将最高位的1后面的bit串全变为1,进行带符号右移1位,再相减即可。
int reserve_highest_1(int x) {//保留最高位的1 x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x -= (unsigned int)x >> 1; return x; }
3.保留最低位的1:保留x的bit串最低位的1,只需使用x的bit串与-x的bit串间的关系即可,x与-x的bit串只在最低位相同,且均为1.
int reserve_lowest_1(int x) {//保留最低位1 x &= -x; return x; }
4.求出bit串的前导0的数量:要求出xbit串前导0的数量,其思路是先将x>>16==0?,判断最高位是否在前16位;若不在前16位,则将x<<16,将最高位1移到前16来;然后再判断最高位是否在左移后的
bit串前8位....按照此思路,找到最高位的位置,即可得到前导0的数量。
int num_of_leading_0(int x) {//求出最高位1前的0的个数 int n = 0; if ((unsigned int)x >> 16 == 0) { n += 16; x <<= 16; } else if ((unsigned int)x >> 24 == 0) { n += 8; x <<= 8; } else if ((unsigned int)x >> 28 == 0) { n += 4; x <<= 4; } else if ((unsigned int)x >> 30 == 0) { n += 2; x <<= 2; } else if ((unsigned int)x >> 31 == 0) { n += 1; x <<= 1; } if (x == 0) n++; return n; }
5.求bit串中1的数量:在这里使用平移法来计算,这是一种分治思想的应用,先使用一些特殊数字的bit串,计算出相邻位置的1的数量;在使用特殊数字的bit串,计算出每相邻两个位置1的数量;再计算
相邻4个位置、8个位置、16个位置1的数量,即可得到整个bit串中1的数量。
int num_of_one(int x) {//求x的2进制表示中的1的总数,使用平移法 unsigned int ux = x;//转化为无符号类型 ux = ((ux & 0xAAAAAAAA) >> 1) + (ux & 0x55555555);//求出每相邻两位的1的数量 ux = ((ux & 0xCCCCCCCC) >> 2) + (ux & 0x33333333);//求出每相邻两位的1的数量 ux = ((ux & 0xF0F0F0F0) >> 4) + (ux & 0x0F0F0F0F);//求出每相邻四位的1的数量 ux = ((ux & 0xFF00FF00) >> 8) + (ux & 0x00FF00FF);//求出每相邻八位的1的数量 ux = ((ux & 0xFFFF0000) >> 16) + (ux & 0x0000FFFF);//求出每相邻十六位的1的数量 return ux; }
6.反转bit串:反转操作的思路跟上面求bit串中1的数量的相似,都是分治的思想,使用特殊数字的bit串,反转相邻的两个位置,再反转相邻的4个位置,再反转相邻的8个位置,最后是相邻的16个位置。
int reverse(int x) {//反转x的二进制表示形式 x = (unsigned int (x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1);//反转相邻的2位 x = (unsigned int (x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2);//以2位为单位进行反转 x = (unsigned int (x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4);//以4位为单位进行反转 x = (unsigned int (x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);//以8位为单位进行反转 x = (unsigned int (x & 0xFFFF0000) >> 16) | ((x & 0x0000FFFF) << 16);//以16位为单位进行反转 return x; }
下面给出测试以上bit操作的测试代码:
int main() { int a1 = -100; cout << "sign(-100)=" << sign(a1) << endl; int a2 = 100; cout << "sign(100)=" << sign(a2) << endl; int b1 = 402345; cout << "402345的二进制形式为:" << bitset<sizeof(int)*8> (b1) << endl; cout << "402345保留最高位的1后为:" << bitset<sizeof(int)*8>(reserve_highest_1(b1)) << endl; cout<<"402345保留最低位的1后为:"<< bitset<sizeof(int) * 8>(reserve_lowest_1(b1)) << endl; cout << "402345最高位前0的数目为:" <<num_of_leading_0(b1) << endl; cout << "402345的二进制形式中1的总数为:" << num_of_one(b1) << endl; cout << "402345的二进制形式反转输出为为:" << bitset<sizeof(int)*8>(reverse(b1)) << endl; return 0; }