题目描述:Divide two integers without using multiplication, division and mod operator.
译:(除两个数不使用乘除取余)
代码是网上看见的,注释是自己加的,这个写的挺有意思的,但可能有点难懂。
public class Divide_Two_Integers2 {
public static int divide(int dividend, int divisor) {
//除数为0则返回无穷大
if(divisor == 0)
{
return Integer.MAX_VALUE;
}
//这里是判断两个整数是不是同号的简便写法,也可以写成乘法, 但是那样又有越界的可能, 而且乘法的计算复杂度比位运算要高。
//这里是异或,同0异1,int类型32位,向右移31位剩下的就只是符号位,>>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;
//>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
boolean isNeg = (dividend^divisor)>>>31 == 1;
//记录结果
int res = 0;
if(dividend == Integer.MIN_VALUE)
{
//之所以这么做是为了避免下面对dividend求abs时发生溢出,Math.abs(-2147483648) = -2147483648,要避免这种情况
dividend += Math.abs(divisor);
//int的取值范围[-2147483648, 2147483647],即最小值的abs比最大值的abs大1,
//那么,除法却发生溢出的情况仅仅当:dividend=-2147483648,divisor=-1
if(divisor == -1)
{
return Integer.MAX_VALUE;
}
//此处result要记得加1,因为被除数里已经加了一个除数
res++;
}
//当divisor为MIN时,结果要么为1(dividend也为MIN),要么为0
if(divisor == Integer.MIN_VALUE)
{
return res;
}
//取绝对值
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
//记录除数一共向左移了几位
int digit = 0;
//让除数左移直到大于被除数之前得到一个最大的基,左移相当于一个数乘2,右移相当于除2
//这里小于等于被除数的一半原因就是除数再向左移一位就等于乘了2,所以小于等于被除数的一半就是小于被除数之前最大的基
//如果在这个数基础上再乘2,那么就会比被除数大
while(divisor <= (dividend>>1))
{
divisor <<= 1;
digit++;
}
//先用被除数减去刚刚由除数得到的那个最大的基,然后使基不断减小(实质上就是2^digit*divisor,减小的是digit)
//如果剩余的数可以减去这个缩小的基则再减
//同时结果加上2^digit,重复过程直到digit小于零为止,实质上就是求已知除数之外的另一个除数的二进制表达式,digit就是幂,再转化为十进制。
//如87/4得到digit=4,按上述方法求得到result=1*2^4+0*2^3+1*2^2+1*2^0=21,至于系数是0或1则是if里的代码控制
while(digit>=0)
{
if(dividend>=divisor)
{
res += 1<<digit;
dividend -= divisor;
}
divisor >>= 1;
digit--;
}
//判断正负返回结果
return isNeg?-res:res;
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int num1=sc.nextInt();
int num2=sc.nextInt();
System.out.println(divide(num1,num2));
}
}