美文网首页编程派
代码的力量 | 异或的妙用

代码的力量 | 异或的妙用

作者: 羽墨志 | 来源:发表于2019-11-20 21:36 被阅读0次

    考虑如下情形,对一个无符号数num的指定位进行取反。

    假设对num的第3位进行取反,程序运行过程中我们并不知道num第三位的取值情况,所以需要分情况讨论,很容易会想到如下实现方法:

    unsigned char num;
    
    if(num&0x08) // num的第3位为1
    {
        num &= ~0x08; //num = num&(~ 0x08);
    }
    else // num的第3位为1
    {
        num |= 0x08; //num = num | 0x08;
    }
    

    如果要把上面是假设推广到一般情况,由调用者指定要取反的位。为此我们引入一个变量bitNum,用于指定要取反的位,那么我们将得到如下函数:

    unsigned char num;
    
    /*
    *┌───────────────────────────────────────┐                        
    *│ Description  :   main function
    *│ Parameter    :   bitNum -位序号
    *│ Return       :   None
    *│ Author       :   羽墨志
    *└───────────────────────────────────────┘
    */
    void reverseBit(unsigned char bitNum)
    {
        if(num&(0x01<<bitNum))
        {
            //num = &(~(0x01<<bitNum));
            num &= ~(0x01<<bitNum);
        }
        else
        {
            //num = num | (0x01<<bitNum);
            num |= 0x01<<bitNum;
        }
    }
    

    【注】这里之所以不直接num进行赋值,是因为直接赋值不仅改变了目标位的值,同时还可能改变了其他位的值,这是不被允许的。num &= mask;能够确保不改变其他位的前提下把num的对应位变为0,而num |= mask;能够确保不改变其他位的前提下把num的对应位变为1

    虽然实现了功能,总觉得还是不够简洁明了。上面的实现方法核心是位与和位或操作,先通过移位(这里是左移)操作定位到对应的位,而后通过位与操作判断对应位的取值,最后通过位与位或操作改变对应位的值。

    异或运算具有“相同为0,不同为1”的特点,0异或的结果保持不变,与1异或的结果x相当于取非操作。利用这一特点我们可以得到如下实现:

    unsigned char num;
    
    /*
    *┌───────────────────────────────────────┐                        
    *│ Description  :   main function
    *│ Parameter    :   bitNum -位序号
    *│ Return       :   None
    *│ Author       :   羽墨志
    *└───────────────────────────────────────┘
    */
    void reverseBit(unsigned char bitNum)
    {
        // num = num ^ (0x01<<bitNum); 
        num ^= 0x01<<bitNum; 
    }
    

    这样一来就省去了取值判断步骤,大大精简了代码,提高了程序的运行效率。

    位运算总结

    1. 按位与&:同1为1,否则为0。

      & 0 1
      0 0 & 0 = 0; 0 & 1 = 0;
      1 1 & 0 = 0; 1 & 1 = 1;
    2. 按位或|:同00,否则为1

      & 0 1
      0 0 | 0 = 0; 0 | 1 = 1;
      1 1 | 0 = 1; 1 | 1 = 1;
    3. 按位异或^:相同为0,否则为1

      ^ 0 1
      0 0 ^ 0 = 0; 0 ^ 1 = 1;
      1 1 ^ 0 = 1; 1^ 1 = 0;
    4. 按位取反~1001

      ~ 0 1
      ~1 = 0; ~0 = 1;
    5. 移位运算: 将整型或字符型数据作为二进位信息串整体向左或向右移动若干位。

      1. 左移<<:左移运算将一个位串信息向左移指定的位 。
      2. 右移>>:右移运算将一个位串信息向右移指定的位 。

      【注】

      1. 对于无符号数:
        1. 左移时,右端空出的位用0补充,左端移出的位的信息被丢弃;
        2. 右移时,左端空出的位用0补充,右端移出的位的信息被丢弃。
      2. 对于有符号数:
      3. 对于正整数(符号位为0),右移时,左端空出的位也用0补充;
      4. 对于负整数(符号位为1),右移时,左端空出的位用0或用1补充,取决于计算机系统。
        1. 负数右移,左端空出的位用0 补充的系统称为“逻辑右移”;
        2. 负数右移,左端空出的位用1补充的系统称为“算术右移” 。
        3. 判断方法:
      5. 在二进制数的位运算中,在信息没有因移动而丢失的情况下,每左移1位相当于乘以2, 每右移1位,相当于除以2
    6. 运算优先级

      1. 取非~、位与&、异或^、位或|的运算优先级依次降低, 其中取非~的结合方向自右至左,且优先级高于算术运算符,其余运算符的结合方向自左向右,且优先级低于关系运算符。
      2. 移位运算符的优先级低于算术运算符,高于关系运算符,其结合方向是自左向右。

      即运算优先级顺序为:取非运算符~>算术运算符>移位运算符>关系运算符>位与&>异或^>位或|

    相关文章

      网友评论

        本文标题:代码的力量 | 异或的妙用

        本文链接:https://www.haomeiwen.com/subject/ilpaictx.html