文章目录
- 通过加减法、移位实现整数乘、除法(仅仅保留商)
- 1. 先导
- 2. 非负整数的乘除法
- 2.1 乘法
- 2. 2 除法
- 3. 整数的乘法(位运算实现)
- 3.1 乘法
- 3.2 除法
- 4. 参考链接
通过加减法、移位实现整数乘、除法(仅仅保留商)
1. 先导
计算机中,整数的乘法、除法、取模、取余的计算底层均是使用 移位 + 加减法
实现,基于此,我们来实现 32 位的整数乘除法
2. 非负整数的乘除法
2.1 乘法
32 位的乘法,最大值相乘不会超过 64 位,无论是否有符号,但是两个 int
类型的数相乘,结果不会超过 64 位,故使用 64 位的 long
保留结果
// 方法1:仅仅通过加法进行实现乘法
// 缺点:耗时长
public long plus1(int multiplier, int multiplicand) {
if(multiplier == 0 ^ multiplicand == 0) {
return 0;
}
int count = Math.min(multiplier,multiplicand);
int num = Math.max(multiplier,multiplicand);
long res = 0;
for(int i = 0; i < count;i++) {
res += num;
}
return res;
}
// 方法2:通过移位实现乘法
// 缺点:初见难以理解
public long plus2(int multiplier, int multiplicand) {
if(multiplier == 0 ^ multiplicand == 0) {
return 0;
}
long res = 0;
while(multiplier > 0) {
if((multiplier & 1) == 1) {
res += multiplicand;
}
// 乘数右移 被乘数左移 或者 乘数左移 被乘数左移
multiplicand <<= 1;
multiplier >>= 1;
}
return res;
}
2. 2 除法
32 位的非负整数相除,结果不会出现溢出的情况,方法二使用了 long
整型进行了辅助
// 方法1:通过减法实现,返回商
public int divide1(int dividend, int divisor) {
// 除数不为 0
// 除数为 1,余数为 0 考虑边界情况
if(divisor == 1) {
return dividend;
}
int res = 0;
while(dividend >= divisor) {
res += 1;
dividend -= divisor;
}
return res;
}
// 方法2:通过减法实现,使用了 long 数据类型
public int divide2(int dividend, int divisor) {
// 除数不为 0
// 除数为 1,余数为 0 考虑边界情况
if(divisor == 1) {
return dividend;
}
int res = 0;
//使用 long 整型存储除数
long divisorL = (long)divisor;
long dividendL = (long)dividend;
divisorL <<= 31;
int count = 32;
while(count > 0) {
res <<= 1;
if(dividendL >= divisorL) {
dividendL -= divisorL;
res |= 0x00000001;
}
count--;
divisorL >>= 1;
}
return res;
}
3. 整数的乘法(位运算实现)
3.1 乘法
出现负数的情况,将负数转换为正数,再进行计算
public long plus3(int multiplier, int multiplicand) {
if(multiplier == 0 ^ multiplicand == 0) {
return 0;
}
long res = 0;
int sign = 1;
if(multiplicand < 0) {
multiplicand = -multiplicand;
sign = -sign;
}
if(multiplier < 0) {
multiplier = -multiplier;
sign = -sign;
}
while(multiplier > 0) {
if((multiplier & 1) == 1) {
res += multiplicand;
}
// 乘数右移 被乘数左移 或者 乘数左移 被乘数左移
multiplicand <<= 1;
multiplier >>= 1;
}
return res * sign;
}
3.2 除法
- 方法1 使用了
long
整型进行辅助计算,出现边界情况返回正确答案 - 方法2 未使用
long
整型,结果溢出 (Integer.MIN_VALUE / -1)
,返回Integer.MAX_VALUE
29. 两数相除
- 将特殊的情况处理掉,并将被除数和除数转换成负数进行计算,同样也使用位运算的方式进行计算
// 方法1:通过 `long` 整型进行辅助实现,不会出现溢出的情况
public long divide1(int dividend, int divisor) {
// 除数不为 0
// 除数为 1,余数为 0 考虑边界情况
if(divisor == 1) {
return dividend;
}
long res = 0;
//使用 long 整型存储除数
long divisorL = (long)divisor;
long dividendL = (long)dividend;
//记录结果符号
int sign = 1;
if(dividendL < 0) {
dividendL = -dividendL;
sign = -sign;
}
if(divisorL < 0) {
divisorL = -divisorL;
sign = -sign;
}
divisorL <<= 31;
int count = 32;
while(count > 0) {
res <<= 1;
if(dividendL >= divisorL) {
dividendL -= divisorL;
res |= 0x00000001;
}
count--;
divisorL >>= 1;
}
return res * sign;
}
//如果仅仅通过 32位 的 int 型整数进行计算,溢出的情况下,返回 Integer.MAX_VALUE(Integer.MIN_VALUE / -1)
public int divide2(int dividend, int divisor) {
// 被除数为零的情况
if(dividend == 0) {
return 0;
}
// 除数为1的情况
if(divisor == 1) {
return dividend;
}
// 排除除数为 INT 最小值的情况
if(divisor == Integer.MIN_VALUE) {
return dividend == Integer.MIN_VALUE ? 1 : 0;
}
// 结果值可能溢出的情况
if(divisor == -1) {
return dividend == Integer.MIN_VALUE ? Integer.MAX_VALUE : -dividend;
}
// 将整数转换成负数
int sign = 1;
if(dividend > 0) {
sign = -sign;
dividend = -dividend;
}
if(divisor > 0) {
sign = -sign;
divisor = -divisor;
}
int res = 0;
while(divisor >= dividend) {
int temp = -divisor;
int resT = 1;
while((temp << 1) > 0 && -1 * (temp << 1) > dividend) {
resT += resT;
temp <<= 1;
}
res += resT;
dividend += temp;
}
return res * sign;
}