2.6 位运算

程序中所有的数在计算机内存中都是以二进制的形式存储的。位运算其实就是直接对整数在内存中的二进制位进行操作,例如,6对应的二进制数是110,11对应的二进制数是1011,那么,6 & 11的结果是2,这是二进制对应位进行逻辑与运行的结果。Python中的位运算主要包括下列几种:

(1)<< 按位左移

(2)>> 按位右移

(3)& 按位与

(4)| 按位或

(5)^ 按位异或

(6)~ 按位取反

接下来,本节将针对这几种位运算进行详细讲解。

2.6.1 按位左移

按位左移指的是二进制位全部左移n位,高位丢弃,低位补0。符号“<<”是按位左移的符号,例如,x << n表示x的所有二进制位向左移动n 位,移出位删掉,移进的位补零。以十进制的9为例,它转换为二进制数是00001001,将9左移4位,其结果如图2-13所示。

图2-13 按位左移

从图2-13中可以看出,二进制数0000 1001左移4位后的结果为10010000。为了验证上述结果是否正确,我们通过代码来验证一下,具体如下:

>>> a=9

>>> bin(a<<4) // 将9左移4位

'0b10010000'

值得一提的是,左移n位相当于乘以2的n次方,如果我们希望快速计算一个数乘以2的n次方,可以借助按位左移实现。

2.6.2 按位右移

按位右移指的是将二进制位全部右移n位,移出的位丢弃,移进的位补符号位。按位右移的符号位保持不变。符号“>>”是按位右移的符号,以十进制的8为例,它转换为二进制数是00001000,将8右移2位,其结果如图2-14所示。

图2-14 按位右移

从图2-14中可以看出,当将00001000右移2位后,结果为00000010。为了验证结果是否正确,接下来,在代码中进行测试,具体如下:

>>> a=8

>>> bin(a>>2)  // 将8右移2位后的结果转换为二进制

'0b10'

从结果可以看出,8右移2位后,相当于除以4,结果为2。

需要注意的是,按位右移n位相当于除以2的n次方,如果我们想快速计算一个数除以2的n次方,可以借助按位右移实现。

2.6.3 按位与

按位与指的是参与运算的两个数各对应的二进制位进行“与”的操作。只有对应的两个二进制位都是1时,结果位就为1,否则结果位为0。符号“&”是按位与的符号,接下来,以9和3为例,进行按位与操作,如图2-15所示。

从图2-15中可以看出,当将00001001与00000011进行按位与操作后,结果为00000001。为了验证结果是否正确,接下来,在代码中进行测试,具体如下:

>>> a=9

>>> b=3

>>> bin(a&b)

'0b1'

从结果可以看出,9和3进行按位与操作后,结果为十进制的1。

2.6.4 按位或

按位或指的是参与运算的两个数各对应的二进制位进行“或”的操作。只要对应的两个二进制位有一个为1时,结果位就为1。当参与运算的是负数时,参与运算的两个数均以补码出现。按位或使用符号“|”表示,接下来,对8和3进行按位或操作,如图2-16所示。

图2-15 按位与操作

图2-16 按位或

从图2-16中可以看出,当将00001000与00000011进行按位或操作后,结果为00001011。为了验证结果是否正确,接下来,在代码中进行测试,具体如下:

>>> a=8

>>> b=3

>>> bin(a|b)

'0b1011'

从结果可以看出,8和3进行按位与操作后,结果为十进制的11。

2.6.5 按位异或

按位异或就是将参与运算的两个数对应的二进制位进行比较,如果一个位为1,另一个位为0,则结果为1,否则,结果位为0。按位异或使用“^”符号来表示,接下来,将8和4进行按位异或操作,如图2-17所示。

从图2-17中可以看出,当将00001000与00000100进行按位异或操作后,结果为00001100。为了验证结果是否正确,接下来,在代码中进行测试,具体如下:

>>> a=8

>>> b=4

>>> bin(a^b)

'0b1100'

2.6.6 按位取反

按位取反就是将二进制位的每一位进行取反,0取反为1,1取反为0。例如,将9按位取反后的结果为−10,接下来,带大家一起分析一下9按位取反后为什么结果为−10,具体如下:

(1)将9转换为二进制,变成00001001。因为正数的原码=反码=补码,真正存储的时候,存储的就是00001001;

(2)对9的补码00001001进行取反操作,取反后结果为11110110,这是补码;

(3)将补码转为原码。转换的时候,符号位不变,其他位取反,然后+1 得到原码,结果为10001010,即−10。

具体过程如图2-18所示。

图2-17 按位异或

图2-18 按位取反

从图2-18中可以看出,当将00001001按位取反后,结果为10001010。为了验证结果是否正确,接下来,在代码中进行测试,具体如下:

>>> a=9

>>> ~a

-10

>>> bin(~a)

'-0b1010'

从上述代码可以看出,9按位取反后,结果为−10,而−10转换为二进制数就是10001010。