首先实现加运算,实现加运算自然就可以实现减运算了。位运算是对二进制进行的操作,两个二进制数相加,如果同位都是1,则产生进位。如果同位都不是1,则不产生进位。
1).不考虑进位的情况,两个二进制数相加就是求异或的操作。即对于5+9等价于
00101 + 01001;两者异或结果为01100(异或结果);
2).考虑进位如何操作,同上述情况一样,5+9会在末尾位产生进位,那么我们对两者求与操作,并左移一位可以得到,
00010;这就是产生的进位。再通过和01100(异或结果)进行异或操作,便可得到01110,该结果便是14即它们的和。
为了更好的理解怎么写代码,我们再找一个例子分析下:17+18;并且分别记它们为num1,num2.
num1 = 00010001; num2 = 00010010;
它们的异或结果nOne = num1^num2 = 00000011;(3)
它们的进位情况:nTwo = (num1&num2)<<1 = 00100000(32)
我们令num1 = nOne; num2 = nTwo; 那么继续对num1和num2求异或:nOne = num1^num2 = 00100011(35);
再考虑num1和num2的进位情况:
nTwo = (num1&num2)<<1 = 00000000(即没有产生进位)
此时代码如何编写就明了了,我们可以循环的对两个数字做异或和求进位情况的操作,直到它们不产生进位为止。如果还有些不明白,那么就自己分析下11+15;就会明白之间的关系了。
int Add(int num1, int num2)
{
int nOne = 0;
int nTwo =0;
do
{
nOne = num1^num2;
nTwo = (num1&num2)<<1;
num1 = nOne;
num2 = nTwo;
}while(nTwo != 0);
return num1;
}
至于减法运算,那就比较好理解了,减法运算可以利用加法运算实现,即a-b等价于 a+(-b)。而负数在计算机中的二进制是用补码表示的,一个负数就是它的绝对值的反码加一。
所以减法运算的实现如下:
int Min(int num1, int num2)
{
int temp =0;
temp = Add(~num2,1);
return Add(num1, temp);
}
当然位运算还可以实现很多其他的运算方法,比如交换两个数的值。假设两个数为a,b;那么
a = a^b;
b = a^b;
a = a^b;
就可以达到交换两个数的值得目的(swap)。
下面总结下位运算的简单用途:位运算包括&,|,^,<<,>>.
1. 去掉最后一位:让二进制数右移一位 >>1。
2. 在最后一位加一个0:左移一位<<1。
3. 在最后一位加一个1:左移一位二进制数,并同1<<1的二进制求或运算。
4. 最后一位取反:求二进制数据和1的异或
5. 把右数第k位变成1:先对1<<(k-1);然后与原二进制数求或运算
6. 把右数第k位变成0:先对1<<(k-1),再取反;然后与原二进制求与运算
7. 右数第k位取反:先对1<<(k-1),然后与原二进制数求异或运算。
8. 取末三位:令原二进制数与00111(7)求与运算
9. 取末k位:令原二进制与011..11(k个1)。注:求具有k个1的二进制数:
i = 0;
num = 1;
while(i
{num = (1<<1) +1;
i++;}
10. 取右数第k位:原二进制数右移k-1位,并与1求与
11. 把末k位变成1:原二进制数与同9所说的二进制求或
12. 把右边连续的1变成0:原二进制数和原二进制数+1求与操作
13. 把右起第一个0变成1:x or(x+1);x为原二进制数。
14. 把右边连续的0变成1:x or(x-1);
15 .取右边连续的1:(x异或 (x+1)) >>1
16 .去掉右起第一个1的左边:x and (x xor(x-1));