如何不使用+,-运算符号计算两个数之和?
在编程语言中除了+,-等符号运算,还有位运算.
^,异或,相同为0,不同为1.
比如 : 2^3
0 0 1 0
0 0 1 1
_______
0 0 0 1 (相同出0,不同出1,结果=1)
2^3 = 1;
&,与,同1出1,有0为0.
比如 2&3
0 0 1 0
0 0 1 1
_______
0 0 1 0 (同1出1,有0出0,结果为2)
2&3 = 2;
<<,向左位移.
比如 2<<1
0 0 1 0
_______
0 0 1 0 0 (左移1位,低位用0补齐,结果是4)
2 << 1 = 4;
由于正数的源码,补码,反码都一样,相对简单,来分析一下如果是负数的左移
比如
-3 << 2
在计算机中所有数字都以补码存储:
所以对于数字-3有,
源码: 10000000 00000000 00000000 00000011;
反码: 11111111 11111111 11111111 11111100; (符号位不变,其他位按位取反)
补码: 11111111 11111111 11111111 11111101; (最低位+1,-3在计算机中的实际存储)
左移2位后的补码:
11111111 11111111 11111111 11110100; (左移2位,低位用0补齐,最高位为符号位)
反码: 11111111 11111111 11111111 11110011;(补码-1)
源码: 10000000 00000000 00000000 00001100; (结果为-12)
-3 << 2 = -12;
>>,向有位移.
比如 2>>1
0 0 1 0
_______
0 0 0 1 (右移一位,结果为 1)
2 >> 1 = 1;
比如-3 >> 2
我们已经知道-3的补码为:11111111 11111111 11111111 11111101;
右移两位:11111111 11111111 11111111 11111111; (负数符号位不变,右移两位,高位用1补齐)
反码:11111111 11111111 11111111 11111110; (补码-1)
源码:10000000 00000000 00000000 00000001; (反码取反,结果等于-1)
-3 >>2 = -1;
>>>无符号右移.
比如 2>>>1
0 0 1 0
_______
0 0 0 1 (无符号左移1位,结果为1)
2>>>1 = 1;
>>>与>>唯一的不同是它无论原来的最左边是什么数,统统都用0填充。(包括负数)
比如 -3 >>> 5;
已知-3的补码为:11111111 11111111 11111111 11111101;
无符号右移5位:00000111 11111111 11111111 11111111; (高位用0补充)
源码:00000111 11111111 11111111 11111111; (最高位是0表示正数,正数原反补码一致)
结果为:
1*2的26次方+ 1*2的25次方 +....+1*2的0次方 = 134217727;
-3>>>5 = 134217727;
那么基本的位运算现在我们都已经了解了.来看前面提出的问题:
比如 2 + 3 = 5;
而我们知道 (2+3也可以使用位运算)
0 0 1 0
+ 0 0 1 1
_______
0 1 0 1 (结果等于5)
而 2^3
0 0 1 0
0 0 1 1
_______
0 0 0 1 (可以表示为2+3逐位相加后除进位外剩下的数字 1+0=1=1^0)
而 2&3
0 0 1 0
0 0 1 1
_______
0 0 1 0 (可以表示为2+3逐位相加后的进位1+1=0(进位1=1&1),只不过结果应该左移1位,即 2&3<<1)
0 1 0 0 (左移一位)
然后将异或的结果和左移一位后的与结果相加
0 1 0 0
+ 0 0 0 1
___________
0 1 0 1 (结果等于5,此时的加法重复上面的运算 即 2+3 = 2&3<<1+2^3 = 4&1<<1 + 4^1)
什么时候应该结果重复运算?
当进位结果等于0时,运算结束,得到结果:
0 1 0 0
0 0 0 1
___________
0 0 0 0 (4&1<<1 = 0 结束,此时4^1 = 5,所以3+2 = 5)
java代码如下
int sum (int a, int b){
int sum = a^b;
int cur = a&b<<1;
if(cur==0)return sum;
retturn (sum,cur);
}
最后我们终于完成了3+2=5!!!!!!!!!!!!!!!!!!!!太难了,哈哈哈