位操作

来源:互联网 发布:软件对比分析 编辑:程序博客网 时间:2024/05/29 15:39
6种位运算:  
        &       与运算  
        |       或运算  
        ^       异或运算  
        ~       非运算(求补)  
      >>       右移运算  

      <<       左移运算   

1、& 与运算

    双目运算,两者为1才为1。

2、| 或运算

    双目运算,两者有1即为1。可用于合并标志位。

3、^异或运算

    双目运算,相同为0,不同为1。可用于翻转某一位,例如0011^0010=0001 就是把第二位翻转。

4、>>右移运算

    双目运算,相当于除以2的n次幂

5、<<左移运算

    双目运算,相当于乘以2的n次幂


位运算应用:

1、异或运算交换两个数的值。

    例如a=3(0011),b=4(0100)

        a = a ^ b;(a=0111)
        b = b ^ a;(b=0011) //
        a = a ^ b;(a=0100)

    公式分析:

      异或运算满足结合律和交换律。

      因此上式2展开等价于 b=b^a^b=a^(b^b)=a^(0000)=a;

      式3中展开 a=(a^b)^(b^a^b)=a^b^a=b;

    内存角度上分析:

        初始a地址存放3,b地址存放4;然后将a地址存放3与4的差别,此时b仍然存放4;然后4与3和4的差别异或运算,有差异的位为1,其余为0,那么相当于把b中所以存在差异的位翻转,无差异的位不变,显然结果为初始a地址的值3;此时b地址存放的值为3,a仍然存放3与4的差异,那么同样将差异与b中的值3异或运算将得到4,并放入a。因此完成了交换运算。

#define SWAP(a,b)  a=a^b;\                    b=b^a;\                    a=a^b;\
2、判断整数奇偶性:
    

    判断整数的奇偶性,常规的整数奇偶性判断是使用取余数操作,例如:

#define PARITY(value) (value%2==1)

   而实际上有这样一个规律,基数的最低位总是为1,偶数最低位总是为0,因此可以这样判断奇偶性:

#define PARITY(value) (value&1)

3、判断整数是否为2的整数幂

    即整数只有一位为1,其余为0,例如 2、4、8、.....

    常规操作:遍历2的整次幂并比较是否相同

#include "math.h" template<class Type>bool IsPowerOfTwo(Type value){for(int i = 0,l = 8*sizeof(value); i < l ;i++){if(pow(2,i) == value){return true;}} return false;}
    而这类数据有这样的规律:n&(n-1)总是为0,1是特殊情况,因此上式简化为

 #defineISPOWEROFTWO(n) ((!(n&(n-1)) ) && n)
4、统计n中1的个数

  常规办法:判断n的奇偶性,为奇数则统计个数加1,然后n右移1位,只到n为0。

template<class Type>inline bool Parity(Type value){return (value % 2 != 0);}template<class Type>inline int CountOne(Type value){if(value != 0){return Parity(value) + CountOne(value >> 1);}return 0;}
    优化方法:

   考虑2位整数 n=11,里边有2个1,先提取里边的偶数位10,奇数位01,把偶数位右移1位,然后与奇数位相加,因为每对奇偶位相加的和不会超过“两位”,所以结果中每两位保存着数n中1的个数;

    相应的如果n是四位整数 n=0111,先以“一位”为单位做奇偶位提取,然后偶数位移位(右移1位),相加;再以“两位”为单位做奇偶提取,偶数位移位(这时就需要移2位),相加,因为此时没对奇偶位的和不会超过“四位”,所以结果中保存着n中1的个数;

    依次类推可以得出更多位n的算法。整个思想类似分治法。

int CountOne(unsigned long n){    //0xAAAAAAAA,0x55555555分别是以“1位”为单位提取奇偶位    n = ((n & 0xAAAAAAAA) >> 1) + (n & 0x55555555);    //0xCCCCCCCC,0x33333333分别是以“2位”为单位提取奇偶位    n = ((n & 0xCCCCCCCC) >> 2) + (n & 0x33333333);    //0xF0F0F0F0,0x0F0F0F0F分别是以“4位”为单位提取奇偶位    n = ((n & 0xF0F0F0F0) >> 4) + (n & 0x0F0F0F0F);    //0xFF00FF00,0x00FF00FF分别是以“8位”为单位提取奇偶位    n = ((n & 0xFF00FF00) >> 8) + (n & 0x00FF00FF);    //0xFFFF0000,0x0000FFFF分别是以“16位”为单位提取奇偶位    n = ((n & 0xFFFF0000) >> 16) + (n & 0x0000FFFF);    return n;}
    看起来似乎采用位运算的代码比朴素方法代码要复杂的多,但是在性能上有着朴素方法无法比拟的优越性,只要四步简单的运算就能达到目的,而朴素方法不是用循环就是递归,这大大降低了CPU的运算性能。
5、正整数的模运算(负整数不适用)

6、循环位移

    例如数n,循环左移k位:a=a<<k|a>>sizeof(a)-k;

    循环右移k位:a=a>>k|a<<sizeof(a)-k;


0 0
原创粉丝点击