十进制下:5 + 7 = 12
5: 0101
7: 0111
二进制下两数求和,分三步:
各位值相加,不算进位值,二进制亦或运算计算进位值,二进制与运算,然后左移一位;对1,2步的结果,重复以上两步骤两数之和就是不计算进位值加上进位值,直到没有进位
第二部为什么要左移?
jjdxtg在十进制下计算5+7时,进位向前一位进1,也就是相当于左移
5 + 7的详细计算:
第一次:
亦或:0101^0111 = 0010,没有进位的值。
与:0101&0111 = 0101,等于1的位说明这一位是要产生进位的。而进位是要向前进一位,所以要左移,
0101 ,两个位置为1,说明是有两个位置需要进位,左移运算,0101<<1 = 1010
第二次:
0010^1010 = 1000
(0010&&1010)<<1 = 0100 # 还有进位,需要继续加
第三次:
1000^0100 = 1100
(1000&&0100) <<1= 0000 # 没有进位
进位为0,返回第一步的结果。
1.2 负数博客上好多教程都是以正数为例来解释,让好多读者误认为二进制的运算是在源码上进行的。
实际情况是用补码运算的!!!
因为正数的源码、反码、补码是相等的,所以大家误认为是用的源码。
python3 中最高位1表示负数,最高位0表示正数
(个人认为,用补码运算是因为可以把符号位直接参与运算)
源码转化成补码:源码转化成反码(符号位1不变,其他位改变),然后反码+1
补码转化为源码:你只需要记住,补码的补码就是源码
所以补码转反码,然后+1
例如 -2 + 8
用8位二进制表示:
-2 源码 :1000 0010;反码:1111 1101;补码:1111 1110
8 源码/反码/补码:0000 1000
用补码运算结果如下:
1、1111 1110^0000 1000 = 1111 0110 (负数)转化成源码:1000 1010 = -10
2、(1111 1110&0000 1000)<<1 = 0001 0000 (正数),源码和补码一样:0001 0000 = 16
这是用补码运算的例子。
继续运算:
进位为16,继续计算1,2步,你会发现进入死循环。
因为:python3实现不会溢出,溢出的最高位不会舍弃掉。详细请看博文:https://www.jianshu.com/p/21fd1598d4ae
这种方法在c,c++,java中没有问题。但在python3中会有问题,python3存的正数是无限大的
2 python代码python位运算
与 & 或 | 非 ~ 亦或 ^ 左移 << 右移 >>
# -*- coding:utf-8 -*-class Solution: def Add(self, num1, num2): # write code here if not num1: return num2 elif not num2: return num1 while num2: num1,num2 = (num1^num2)&0xFFFFFFFF, (num1&num2)<<1 if num1>>31 ==0: return num1 else: return num1 - 4294967296为什么还要 - 4294967296,因为2**32 = - 4294967296。
下面详细解释:
回到前面:
咱们计算两个数相加是用的二进制,而且是二进制的补码,
如果直接输出就是把补码直接转化成十进制(中间没有转化成反码+1)。
但是我们最后要输出的是源码的十进制,所以中间少了一步转化成源码的步骤。
之前的计算:1111 1110^0000 1000 = 1111 0110 (负数)转化成源码:1000 1010 = -10
1111 0110 直接转化成十进制是246,而我们想要的结果是-10
你会发现246-256 = -10,这就是我们的结果。
为什么减去256,和我们的位数8有关,2**8 = 256
在程序中,我们用的是32位,所以减去2**32.
而正数因为源码,反码,补码都相等就不会出现这个问题。
查了好久的资料终于解决问题了,吃饭去了!!!