最近在写leetcode算法题,接触到一些题目用按位操作会比较好,因此了解了一下python3底层的数字表示。
发现有一些需要注意的地方。
1.数字都是以补码的形式存储在底层,因此处理负数的时候要特别小心。
为啥要以补码:因为这样可以在底层把减法变成加法,让计算机做减法是很困难的。
加法:
整数: [A]补 + [B]补 = [A+B]补 (mod 2^(n+1))
小数: [A]补 + [B]补 = [A+B]补 (mod 2)
减法:
整数: [A-B]补 = [A]补 + [-B]补 (mod 2^(n+1))
小数: [A-B]补 = [A]补 + [-B]补(mod 2)
————————————————
整数的补码还是整数没啥问题,但是负数的补码是原码的反码+1,这样处理的时候没注意到就会有问题。
补码:整数的补码是原码,负数的补码是原码的反码+1。反码是原码每个位取反。
例子:
>>> (-7)>>1 # -7的原码反码补码: 10000111 11111000 11111001
-4
>>> 7>>1 # 7的源码反码补码: 00000111 00000111 00000111
3
因为底层使用补码表示,所以这就是为啥-7>>1不是想象中的-3, (-7右移一位是10111100,这个数的原码是 反码: 10000011 +1 =1000100,所以是-4)
包括任何的位操作 & ^ 这些其实都是在对补码进行操作。
不要以为3是 0 0011 然后 -3 是 1 0011, 这只是我们习惯上用来的表示,存在计算机里面的不是这样的,不注意就出问题。
2.python3不像C++这些整型有固定位数,因此处理的时候需要注意。
比如说C++通过一直左移动可以让数变为0,但是python3的话一直左移就一直除2,要实现和C++同样的效果要 num&0xffffffff.