从整数的补码到用位运算实现任何两个数的加减法

在计算机中,数值是以补码的形式存储的,正整数的补码就是其原码,负整数的补码就是其绝对值的原码所有位取反再加1。

例如:-7的补码:因为是负数,则符号位为“1”,整个为10000111;其余7位为-7的绝对值+7的原码
0000111按位取反为1111000;再加1,所以-7的补码是11111001。简单点就是10000000( 128)-0000111(7)=11111001(121)

由上面的例子也可以知道,要求一个负整数的补码,在一个字节大小的情况下,只需要求128减去该负数的绝对值所得到的差的原码就行。

计算机之所以要把负数存储为其补码,是因为想把减法变成加法,这样减去一个负数,就相当于加上该负数的补码。

想要将一个正整数取反的话,那么只需要对该正整数按位取反再加1就可以了,相反的,如果是负整数转正整数的话,就是先减一在按位取反,下面的c语言的整数取反代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>  
int change(int num)
{

if (num < 0)
{
num = ~(num - 1);
}
else if (num >0)
{
num = ~num + 1;
}
return num;
}

现在来看看怎样通过位运算来实现连个整数的加法。

我们知道,在位的角度来看加法,一个位加后,要么需要进位,要么不需要,需要进位的是因为两个加数相同的位的值都是1,不需要进位是因为相同位的值不都是1,不需要进位的情况下,只需要两个数进行异或运算就可以了,进位的情况下,需要两个加数先进行&运算,得到进位的值,在左移一位,这样再递归的进行两个数的相加,知道没有进位为止,也就是两个加数&运算后的值为0。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int add (int a , int b) {

return b ? add ((a ^ b) , (a & b)<<1) : a ;
}

int main(int argc, char *argv[])
{

int a , c ;

scanf ("%d%d",&a , &c) ;

printf ("val = %d\n" , add (a , c) );

return 0;
}

如果想要实现两个整数相减的话,那么可以利用补码的思想,先将减数取反,得到其补码,在利用上面的加法进行求和。