采用书籍Python核心编程(第二版),人民邮电出版社,2008年7月第1版。本书以Python2.5为主,但笔记主要以Python3.6为主。

一、Python位运算操作符

Python支持标准位运算,位运算操作符只能用于整数。操作符如下:

操作符

意义

举例

操作符

意义

举例

~

按位取反

~5

&

按位与

5&6

|

按位或

5|6

^

按位异或

5^6

<<

左移m位

5<<1

>>

右移

6>>1

二、原码反码补码

原码反码补码的一般说法:

  1. 原码:原码是二进制数字的一种简单的表示法。二进制首位为符号位,1代表负,0代表正。
  2. 反码:反码可由原码得到。如果是正数,反码与原码相同;如果是负数,反码是其原码(符号位除外)各位取反而得到的。
  3. 补码:补码可由原码得到。如果是正数,补码与原码相同;如果是负数,补码是对其原码(除符号位外)各位取反,并在末位加1而得到的(有进位则进位,但不改变符号位)。

但是为什么会有原码、反码、补码呢?简单来说,原码是为了方便人计算,补码是方便计算机计算,而反码是认为提出的一个中间桥梁。参考这篇文章:原码、反码和补码,总结几点:

  1. 计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行。
  2. 用补数代替原数,可把减法转变为加法。出现的进位就是模,此时的进位,就应该忽略不计。
  3. 二进制下,有多少位数参加运算,模就是在 1 的后面加上多少个 0。
  4. 补码就是按照这个要求来定义的:正数不变,负数即用模减去绝对值。
  5. 举例:以10为模,6的补码是6,-6的补码是4。9-6=9+(-6)=9+(10-6)=9+4=13,13%10=3,结果为3,完全正确!
  6. 举例:8位二进制的模是100000000,3的补码是00000011,-3的补码是11111100(100000000-00000011)。

以 8 位二进制举几个简单例子:

整数

原码

反码

补码

27−1=127

2 7 − 1 = 127

01111111

01111111

01111111

+7

00000111

00000111

00000111

+1

00000001

00000001

00000001

+0(同0)

00000000(同0)

00000000(同0)

00000000(同0)

0

00000000

00000000

00000000

-0(错误)

10000000(错误)

11111111(错误)

10000000(错误)

-1

10000001

11111110

11111111

-7

10000111

11111000

11111001

−(27−1)=−127

− ( 2 7 − 1 ) = − 127

11111111

10000000

10000001

表格有两个错误表示:+0和-0,但是给 0 加正负号根本没有意义。我们不会讨论 +0 或 -0 的原码反码和补码,因为这二者本来就是 0。所以,0(包括+0、-0)的原码反码和补码都是00000000

数字在计算机中用二进制补码形式表示,补码10000000表示的不是 -0,而是-128。用参考资料中的“模理论”来说明,-128的补码的计算方法:模的二进制-绝对值的二进制(100000000-10000000)=10000000。

三、Python位运算

数字在计算机中是以补码保存的,所以用Python位运算作用在补码上,每一位都参与运算:

  1. 按位取反~:按位取反后得到二进制表示,把该二进制看成一个新的补码,返回该补码对应的数字结果。
  2. 按位与&,或|,异或^:同取反~
  3. 左移<<和右移>>:左移和右移N位等同于无溢出检查(忽略溢出)的N次幂运算2**N。对长整型来说,位操作符使用一种修改的二进制补码形式,使得符号位可以无限向左扩展。也就是说,向左移位不会溢出。

Python位运算举例:

>>> ~7 # 解释:7的补码是00000111 对补码取反得到11111000 该补码对应的整数为-8
-8
>>> ~-7 # 解释:-7的补码是11111001 对补码取反得到00000110 该补码对应的整数为6
6
>>> 6 & 5 
4
>>> 5 & 4
4
>>> 7 << 2
28
>>> 28 << 2
112

【补充1】原码到反码再到补码的计算很简单,但是补码如何变回到原码呢?

  • 答:补码的补码就是原码啊。如果补码首位为0,表示该数字为正数,原码反码都与补码相同。如果补码首位为1,表示该数字为负数,对补码再进行一次取反和末位加1操作即可得到原码。得到原码,即可得到该数字。

【补充2】整数的二进制用二进制补码形式表示,那浮点数呢?

  • 答:浮点数当然也用二进制补码形式表示啦。可以参考另一篇博客 由Python浮点数溢出问题到二进制

参考资料:

  1. 原码、反码和补码
  2. 原码、反码、补码的产生、应用以及优缺点有哪些?