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

 

posted @ 2021-04-11 00:21  德哥来了  阅读(833)  评论(0编辑  收藏  举报