整数除法实现(禁乘/除/模/对数):负数边界值处理异常求助
我尝试实现一个不使用乘法、除法、取模、对数运算的整数除法方法int divide(),但遇到了负数边界值处理问题:当处理上下边界值时,Math.abs()返回负数,即使乘以-1也无法转为正数(变量div显示负值),但在main()方法中调用Math.abs()却能正常工作。
问题代码
public class Mass { public static int divide(int dividend, int divisor) { int ans =0; long val = Math.abs(divisor); long div = Math.abs(dividend); System.out.println(div); for(int i =1;i<=div;i++){ val--; if(val ==0){ ans++; val = Math.abs(divisor); } } if((dividend<0 && divisor >0 ) || (dividend >0 && divisor<0) ){ ans = ans *(-1); } return ans; } public static void main(String[] args) { int a= divide(-2147483648, -2); System.out.println(a); } }
问题根源
Java中int类型的取值范围是[-2147483648, 2147483647],也就是最小值是-2^31,最大值是2^31-1。当调用Math.abs(-2147483648)时,由于2147483648超出了int的最大值范围,无法用int类型存储,所以Math.abs会直接返回-2147483648(没有对应的正数能存进int)。
你代码里的核心问题是:Math.abs(dividend)接收的是int参数,返回值也是int类型,即便你把结果赋值给long变量,这个返回值已经是溢出后的-2147483648了,转成long自然还是负数。而在main里直接调用时,你可能只是把结果输出到控制台——控制台会按补码规则解析这个int值,看起来像正数,但变量本身实际还是负数。
修复方法
要正确处理边界值,需要先把int类型的被除数、除数转成long类型,再取绝对值:
long val = Math.abs((long) divisor); long div = Math.abs((long) dividend);
先将int提升为long后,long的取值范围足够覆盖int的边界值,Math.abs就能返回正确的正数了。
另外,当前的循环实现效率极低,比如当被除数是2147483647、除数是1时,要循环20多亿次,完全无法实际使用。可以改用位移法模拟除法:通过不断将除数左移(等效于乘以2)找到最大的不超过被除数的倍数,累加倍数后用被除数减去该值,重复此过程直到被除数小于除数,时间复杂度能降到O(log n)。
内容的提问来源于stack exchange,提问作者SBM

