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

代码的力量 | 异或的妙用

作者: 羽墨志 | 来源:发表于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