采用书籍Python核心编程(第二版),人民邮电出版社,2008年7月第1版。本书以Python2.5为主,但笔记主要以Python3.6为主。
一、Python位运算操作符
Python支持标准位运算,位运算操作符只能用于整数。操作符如下:
操作符 | 意义 | 举例 | 操作符 | 意义 | 举例 |
~ | 按位取反 | ~5 | & | 按位与 | 5&6 |
| | 按位或 | 5|6 | ^ | 按位异或 | 5^6 |
<< | 左移m位 | 5<<1 | >> | 右移 | 6>>1 |
二、原码反码补码
原码反码补码的一般说法:
- 原码:原码是二进制数字的一种简单的表示法。二进制首位为符号位,1代表负,0代表正。
- 反码:反码可由原码得到。如果是正数,反码与原码相同;如果是负数,反码是其原码(符号位除外)各位取反而得到的。
- 补码:补码可由原码得到。如果是正数,补码与原码相同;如果是负数,补码是对其原码(除符号位外)各位取反,并在末位加1而得到的(有进位则进位,但不改变符号位)。
但是为什么会有原码、反码、补码呢?简单来说,原码是为了方便人计算,补码是方便计算机计算,而反码是认为提出的一个中间桥梁。参考这篇文章:原码、反码和补码,总结几点:
- 计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行。
- 用补数代替原数,可把减法转变为加法。出现的进位就是模,此时的进位,就应该忽略不计。
- 二进制下,有多少位数参加运算,模就是在 1 的后面加上多少个 0。
- 补码就是按照这个要求来定义的:正数不变,负数即用模减去绝对值。
- 举例:以10为模,6的补码是6,-6的补码是4。9-6=9+(-6)=9+(10-6)=9+4=13,13%10=3,结果为3,完全正确!
- 举例: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位运算作用在补码上,每一位都参与运算:
- 按位取反~:按位取反后得到二进制表示,把该二进制看成一个新的补码,返回该补码对应的数字结果。
- 按位与&,或|,异或^:同取反~
- 左移<<和右移>>:左移和右移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浮点数溢出问题到二进制
参考资料: