计算机中的数据以二进制的形式存储,即0、1两种状态。位运算就是直接对整数在内存中的二进制位进行操作。本文将介绍位运算的各操作符以及常见应用。

操作符

&(与)

参加运算的两个数据,按二进制位进行与运算。(两位都为1时才为1,否则为0)

例如 12 和 5 两个数,二进制形式分别为 1100、0101. 逐个按位进行与运算得:0100 = 4. 即 12 & 5 = 4.

|(或)

参加运算的两个数据,按二进制位进行或运算。(两位都为0时才为0,否则为1)

例如 12 和 5 两个数,二进制形式分别为 1100、0101. 逐个按位进行或运算得:1101 = 13. 即 12 | 5 = 13.

^(异或)

参加运算的两个数据,按二进制位进行异或运算。(相同为0,不同为1)

例如 12 和 5 两个数,二进制形式分别为 1100、0101. 逐个按位进行异或运算得:1001 = 9. 即 12 ^ 5 = 9.

~(取反)

参加运算的数据,其各二进制位进行取反运算。(0变成1,1变成0)

例如 5,对于一个 int16 型数据,它的二进制形式为 0 000 0000 0000 0101. 取反后得:1 111 1111 1111 1010(符号位为 1,为负数)将此补码转换为原码得:1 000 0000 0000 0110,十进制为 -6. 即 ~5 = -6.

<<(左移)

参加运算的数据,其各二进制位向左进行移位操作,高位丢弃,低位补0.

例如 5,对于一个 int16 型数据,它的二进制形式为 0 000 0000 0000 0101. 左移 3 位后得:0 000 0000 0010 1000 = 40.

即 5 << 3 = 40.

>>(右移)

参加运算的数据,其各二进制位向右进行移位操作,低位丢弃,对于无符号数,高位补 0,对于有符号数,高位补原来的符号位。

  • 例如 5,对于一个 int16 型数据,它的二进制形式为 0 000 0000 0000 0101. 左移 2 位后得:0 000 0000 0000 0001 = 1. 即 5 >> 2 = 1.
  • 例如 -5,对于一个 int16 型数据,它的二进制形式为 1 111 1111 1111 1011. 右移 2 位后得:1 111 1111 1111 1110 = -2. 即 -5 >> 2 = -2.

常见应用

左移、右移实现乘除法

由左移、右移的定义可知,一个二进制数 0000 1010 左移两位后为 0010 1000 = 25 * 23 = 22 * (23 * 21). 由此可见,在数据未溢出的情况下,左移 n 位,相当于原数的值乘以 2n.

同理,右移相当于除以 2n.

异或判断两数符号的异同

判断两个有符号数是同号还是异号,我们可以用条件控制语句进行判断;也可以将两数相乘判断积的正负;同样也可以使用异或运算符。

由于有符号数最高位为符号位,因此在进行异或运算时,两数的符号位也将参与运算。若两数的符号位相同,则异或结果 res 的符号位为 0,即 res >= 0; 若两数的符号位不同,则异或结果 res 的符号位为 1,即 res < 0.

bool isSameSign(int a, int b) {
    int res = a ^ b;
    return res >= 0 ? true : false;
}

与运算判断数的奇偶性

和异或判断两数符号异同类似原理类似,根据二进制数的最低位是 1 还是 0 来判断该数是奇数还是偶数。

要判断一个数 a 的奇偶性,可以先计算 res = a & 1 的值。若 res = 0,则为偶数;若 res = 1,则为奇数。

bool isOdd(int a){
    int res = a & 1;
    return res == 1 ? true : false;
}