將一些運算在位上進行操作,可以加快操作的速度,本博文將使用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; }