只用位运算不用算术运算实现整数的加减乘除运算


只用位运算不用算术运算实现整数的加减乘除运算


给定两个32位整数a和b,可正,可负,可0,不能使用算术运算符,分别实现a和b的加减乘除运算
不考虑溢出

用位运算实现加法

如果不考虑进位,a^b就是正确结果。
在只算进位的情况下,也就是只考虑a加b的过程中进位产生的值是什么,结果就是(a&b)<<1,因为在第i位只有1与1相加才会产生进位。

把完全不考虑进位的相加值与只考虑进位的产生值再相加,就是最终的结果,也就是说,一直重复这样的过程,直到进位产生的值完全消失,说明所有的过程都加完了。


public int add(int a, int b){
    int sum=a;
    while(b!=0){
        sum = a^b;
        b = (a&b)<<1;
        a = sum;
    }
}


用位运算实现减法运算
实现a-b只要实现a+(-b)即可,根据二进制数在机器中表达的规则,得到一个数的相反数,就是这个数的二进制数表达取反加1的结果,,得到b的相反数-b后,再与a进行加法

int negNum(int n){
    return add(~n, 1);
}

public int minus(int a, int b){
    return add(a, negNum(b));
}

 

用位运算实现乘法运算。

a*b的结果可以写成:a*2^0*b0+a*2^1*b1+...+a*2^31*b31
其中,bi为0或1代表整数b的二进制数表达中第i位的值,

举例:a=22=000010110,b=13=000001101,res=0
b的最右侧为1,所以res=res+a,同时b右移一位,a左移一位(左移一位即乘2)
a=000101100, b=000000110
b最右侧为0,所以res不变,b右移一位,a左移一位
a=001011000,b=000000011
b最右侧为1,res=res+a,同时b右移一位,a左移一位。
a=010110000,b=000000001
b最右侧为1,res=res+a,同时b右移一位,a左移一位。
a=101100000,b=000000000
此时b为0,过程停止,返回res=100011110,即286
不管a和b是正,负,还是0,上述过程都是对的,因为都满足a*2^0*b0+a*2^1*b1+...+a*2^31*b31

public int multi(int a, int b){
    int res = 0;
    while(b!=0){
        if((b&1)!=0){
            res = add(res,a);
        }
        a << =1;
        b >>> = 1;
    }
    return res;
}

 

用位运算实现除法运算,其实就是乘法的逆运算。
其实就是找到a能包含的最大部分(指b* 2^x )然后让a减去这个最大部分,再让剩下的a找到次大部分,并依次找下去。以上过程只适用于a和b都不是负数的时候,所以,如果a和b中有一个为负数或都为负数时,可以先把a和b转成正数,计算完后再看res的真实符号是什么就可以。


public int div(int a, int b){
    int x = isNeg(a)?negNum(a):a;
    int y = isNeg(b)?negNum(b):b;
    int res = 0;
    for(int i=31; i > -1; i= minus(i, 1)){
        if((x>>i)>=y){
            res |= (1<<i);
            x = minus(x, y<<i);
        }
    }
    return isNeg(a) ^ isNeg(b)?negNum(res):res;
}


上述方法可以计算绝大多数情况,但32位整数最小值为-2147483648,最小值的绝对值比最大值的绝对值大1,所以,如果a或b等于最小值,是转不成相应正数的,总结如下:
1.如果a和b都不为最小值,直接使用上述过程,返回div(a,b)
2.如果a和b都为最小值,a/b的结果为1,直接返回1
3.如果a不为最小值,b为最小值,a/b结果为0,直接 返回0
4.如果a为最小值,b不为最小值,只能把最小值增加一点,计算出一个结果,然后根据这个结果修正一下,得到最终结果
 

public int divide(int a, int b){
    if (b==0) {
        throw new RuntimeException("divisor is 0");
    }
    if(a==Integer.MIN_VALUE && b==Integer.MIN_VALUE){
        return 1;
    }else if(b==Integer.MIN_VALUE){
        return 0;
    }else if(a==Integer.MIN_VALUE){
        int res = div(add(a, 1), b);
        return add(res, div(minus(a, multi(res, b)), b));
    }else{
        return div(a, b);
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值