1.整数加法
int Add(int a,int b)
{
if(b == 0) return a;//没有进位的时候完成运算
int sum,carry;
sum = a ^ b;//完成第一步没有进位的加法运算
carry=(a & b) << 1;//完成第二步进位并且左移运算
return Add(sum,carry);//进行递归,相加
}
算法思想:比如:255+366
若不考虑进位,则为511,但是同时考虑到某位上的两个数相加大于10的时候需要向高位进1,从而对于问题来说就是个位的5和6相加为11,需要向十位进1,而十位的5+6+1=12需要向百位进1,而百位的2+3+1=6不需要进1.从而最后的结果为511+110=621.
2:整数减法
a-b=a+(-b)首先取减数的补码,然后相加
而补码运算就是 按位取反再加一,既—n=~n+1=~(n-1)
int Minmus(int a,int b)
{
if(b==0)
return a;
b=~b+1;
return Add(a,b);
}
3.整数乘法
乘法就是将乘数写成(2^0)*k0 + (2^1)*k1 + (2 ^2)*k2 + ... + (2^31)*k31,其中ki为0或1,然后利用位运算和加法就可以了。
而取得乘数的二进制表示中的一位,我们可以使用下面的方法:n&(-n)或者是n&~(n-1),这样做的话可以极大地提高时间效率,因为我们不需要从右向左的一个一个位的找乘数
的1位,算法如下:
int Mul(int a,int b)
{
int ans=0;
for(int i=1;i;i<<=1,a<<=1)
if(b&i)
ans+=a;
return ans;
算法思想:比如计算a*b;而b的二进制表示为1*2^0+0*2^1+1*2^3+0*2^4.(只是举个简单的例子)从而将上述的b替换为其二进制表示,则我们可以看出a*1*2^3,其实就是将a的值向左移动三位a<<3,e而a*1*2^0还是为a,从而最终的结果为a+a<<3
注:我在对这个算法进行改进的时候曾经想过这样:
我们知道求一个数的二进制位的从右向左数的第一位1的方法可以这样做:n&(-n)或者是n&~(n-1),但是我突然想到一个问题,就是即使我算出了这个第一位1,但是我却不知道这个第一位到底是位于乘数的哪一位,这样子在对被乘数做左移运算的时候我们就不知道到底该需要左移多少位,这样还是用上面的算法吧。
4;除法就是由乘法的过程逆推,依次减掉(如果够减的话)divisor << 31、divisor << 30、... 、divisor << 2、divisor << 1、divisor(要保证不能溢出)减掉相应数量的除数就在结果加上相应的数量。
int Div(int dividend, int divisor)
{
// assert(divisor != 0)
int sign = 1;
if(dividend < 0 && divisor > 0 || dividend > 0 && divisor < 0)
sign = -1;
unsigned int x = (unsigned int)abs(dividend);
unsigned int y = (unsigned int)abs(divisor);
int bitCnt = sizeof(int) << 3;
int quotient = 0;
int k = bitCnt-1;
while(((1 << k) & y) == 0) k--;
for(int j = bitCnt-1-k; j >= 0; j--)
{
if(x >= (y << j))
{
x -= (y << j);
quotient += (1 << j);
}
}
return sign*quotient;
}
上面的算法中的那个while循环就是为了保证y在左移的时候不会出现溢出的现象原因在于从上面的while循环中结束之后k的值表示y的二进制表示中从右面数第一个为1的值,这样在下面的循环中才能保证y的不越界性。