如何通过位运算实现加减乘除

141 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

最近看到一个这样的题

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

当时我就蒙了,不用运算符号怎么能得到答案呢?

于是不信邪的我,直接添加代码return dividend/divisor 结果不能通过!!!!

唔,还是老老实实想想其他办法吧。

我们知道,做除法,有这么几种情况:

  1. 被除数为0 返回0
  2. 除数为1 返回被除数
  3. 除数被除数异号 结果为负
  4. 能不能除尽

在题目描述里面,给了提示:整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

也就是不能除尽就截去小数部分。(截去,不是四舍五入哈)

那么先把简单的01情况写了吧。

public int divide(int dividend, int divisor){
if(dividend==0||divisor==1){return dividend;}

}

接下来这么判断符号

boolean k = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);

并且把除数被除数都通过Math.abs()取绝对值。当被除数小于除数时候,标识有小数,进行移位

好像还是一点抽象。 那么我们从简单加法开始

加减乘除

我们可以发现,在二进制位运算里面,异或和求和类似

1^1=0,1^0=1,0^1=1,0^0=0

1+1=0,1+0=1,0+1=1,0+0=0

逻辑运算和求和进位一致

与逻辑运算:1&1=1,1&0=0,0&1=0,0&0=0

求进位运算:1+1=1,1+0=0,0+1=0,0+0=0

那么我们可以根据异或和逻辑和进行加法运算

eg: 3+8 temp=0011^1000=1011; b=(0011&1000)<<1=0000 a=1011=11;

int add(int a,int b){
int temp;
while(b!=0){//b=0就表示没有进位
temp=a^b;
b=(a&b)<<1;
a=temp;
}
return a;
}

减法其实也是加法,不过把减数变成他的补码形式

int sub(int a,int b)
{
	b=~b+1;//将b转换为其补码形式 
	return add(a,b);
}

乘法运算,a*b=b个a相加;

image.png

除法运算:当被除数为0,结果全是0,并且除数不能为0,除法运算很容易想到可以转换成减法运算,即不停的用除数去减被除数,直到被除数小于除数时,此时所减的次数就是我们需要的商,而此时的被除数就是余数。这里需要注意的是符号的确定,商的符号和乘法运算中乘积的符号确定一样,即取决于除数和被除数,同号为正,异号为负;余数的符号和被除数一样

image.png

假设在计算除法时候存在小数也需要进行计算,如果是循环小数,用括号把循环部分括起来,输出字符串

首先如何记录循环?我们可以声明一个map用来标记循环,如果当前mo在map里面,标识出现过,加上括号

如何获取模:被除数%除数

整数部分:两数相除得到 小数部分:余数 * 10 / 除数

可以使用符号情况:

用哈希map判断,若有相同的余数则进入循环

先是极端情况,除数=1;输出被除数,被除数等于0,输出0(被除数)

if(被除数==0||除数==1) return String.valueOf(被除数);

因为可能存在除不尽情况,所以最好用long型;

long chushu=Math.abs((Long)除数)

long beichushu=Math.abs((Long)被除数);

声明返回值类型和存储循环的:

StringBuffer sb=new StringBuffer();

HashMap<Long,Integer> map=new HashMap<>();

先把整数部分加到sb里面

sb.append(beichushu/chushu);

long mo=n%d;

if(mo!=0) sb.append(".");

然后把当前模加入map

map.put(mo,sb.length())

当模不是0,进行循环求模 小数部分:余数 * 10 / 除数先在输出加入余数,然后修改模 mo = mo * 10 % 除数;

接下来判断是不是在map里面u,如果有,加入括号退出循环,如果没有,继续把当前模加入map。

 public String fractionToDecimal(int numerator, int denominator) {
        if (numerator == 0 || denominator == 1)return String.valueOf(numerator) ;
        long n = Math.abs((long)numerator);
        long d = Math.abs((long) denominator);
        StringBuilder sb = new StringBuilder();
        HashMap<Long,Integer> map = new HashMap<>();
        sb.append(n / d);
        long mo = n % d;
        if (mo != 0)sb.append(".");
        map.put(mo,sb.length());
        while (mo != 0){
            sb.append(mo * 10 / d);
            mo = mo * 10 % d;
            if (map.containsKey(mo)){
                sb.insert(map.get(mo),"(");
                sb.append(")");
                break;
            }
            map.put(mo,sb.length());
        }
        return ( (numerator < 0 ^ denominator < 0)  ? "-" : "") + sb.toString();
    }