位运算实现加法和减法——学习笔记

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);
}

 

你可能感兴趣的:(基础算法学习)