位运算实现加法和减法——学习笔记
Leetcode 上看到一道很有意思的题,如何不用“+”和“-”来实现数字的加减运算。
既然不能用“+”和“-”,那么只能用位运算来做了,毕竟追本朔源所有的运算都是由位运算实现的。
由于二进制每一位只有0和1两个状态,因此每一位只有四种可能的运算,分别是:
(1)0+0=0;
(2)1+0=1;
(3)0+1=1;
(4)1+1=0;
我们找找规律就能发现,其实就是对每一位进行了异或^操作。
我们还可以发现只有运算(4)有了进位,由于只有当(1,1)时才有进位,我们可以用与&操作来保存进位。
因此,A+B可以先转化为A^B和A&B两个值,由于A&B是进位值,因此需要整体向前移动一位才算进位,如此一来就得到加法的第一步转化公式:
A+B=A^B+(A&B)<<1;
01+01=00+10;(二进制表示)
我们将^和&操作获得的值重新赋给A和B,利用公式不断将A+B进行转化,直到B=0时加法才算完成了。如下:
(1) A'=A^B;
B'=(A&B)<<1;
(2) A=A'
B=B'
(3) 判断B是否为0,不为0则重新执行(1)
来看个具体的例子:
//任取两数
num1=13;
num2=11;
//二进制
num1: 0 1 1 0 1
num2: 0 1 0 1 1
//位运算操作
x=num1^num2 : 0 0 1 1 0
y=num1&num2 : 0 1 0 0 1
//因为是进位,y要向前移动一位
y=y<<1 : 1 0 0 1 0
//将y当成新的数值继续进行位运算
x2=x^y : 1 0 1 0 0
y2=x&y : 0 0 0 1 0
y2=y2<<1 : 0 0 1 0 0
x3=x2^y2 : 1 0 0 0 0
y3=x2&y2 : 0 0 1 0 0
y3=y3<<1 : 0 1 0 0 0
//当y=0时结束
x4=x3^y3 : 1 1 0 0 0
y4=x3&y3 : 0 0 0 0 0
看起来好像有点复杂,其实只是不断重复相同的几个操作罢了。当A&B等于0时,说明已经不需要进位了,此时已经得到了正确的值了。来看看具体的代码:
int Addition(int num1, int num2) {
int x = num1 ^ num2;
int y = num1 & num2;
while (y != 0) {
y = y << 1;
int temp = x;
x = x ^ y;
y = temp & y;
}
return x;
}
加法搞定,减法其实就不需要写了,毕竟 A-B=A+(-B) 。当然也可以作为练习推一推减法,代码如下:
int Subtraction(int num1, int num2) {
int x = num1 ^ num2;
int y = x & num2;
while (y != 0) {
y = y << 1;
x = x ^ y;
y = x & y;
}
return x;
}
减法似乎更加简洁?当然减法加法只要写一个即可。
当然这里还有个问题,由于不能用“-”,所以当遇到A-B=A+(-B)时,我们也没法像以前那样随便用“-”得到相反数了,根据整型数据的性质我们可以知道:
取相反数就相当于:
-B=~B+1
看代码:
int Opposite(int num) {
return Addition(~num,1);
}
//or
int Opposite(int num) {
return Subtraction(~num,-1);
}
上一篇: FusionChart配置
下一篇: FusionCharts参数设置说明
推荐阅读