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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM