[算法]位运算问题之三(实现加减乘除)
题目:
给定32位整数a和b,可正、可负、可0,不能使用算术运算符,可分别实现a和b的加减乘除运算。
加法运算:
无进位相加:
a: | 001010101 |
b: | 000101111 |
a^b | 001111010 |
只考虑进位:
a | 001010101 |
b | 000101111 |
(a&b)<<1 | 000001010 |
把完全不考虑进位的相加值与只与考虑进位的产生值再相加,就是最后的结果。重复这样的过程,直到进位产生的值完全消失,说明所有的过程都加完了。
public static int add(int a, int b) { int sum = a; while (b != 0) { sum = a ^ b; b = (a & b) << 1; a = sum; } return sum; }
减法运算:
实现a-b其实就是a+(-b),根据二进制在机器中表达的规则,得到一个数的相反数,就是这个数的二进制表达取反加1(补码)的结果。
public static int negNum(int n) { return add(~n, 1); } public static int minus(int a, int b) { return add(a, negNum(b)); }
乘法运算:
res=a*20*b0+a*21*b1+…+a*2i*bi+…+a*231*b31,bi为0或1代表整数b的二进制数表达式中第i位的值。
public static 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; }
除法运算:
b=res*a ==> a=b*20*res0+b*21*res1+…+b*2i*resi+…+b*231*res31
//判断是否为负 public static boolean isNeg(int n) { return n < 0; } //相除的核心算法 public static 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; } //加上特殊情况 public static 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; //分母为最小值,而分子不为最小值,返回0 } 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); } }