通过加减法、移位实现整数乘、除法(仅仅保留商)

通过加减法、移位实现整数乘、除法(仅仅保留商)

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;
    }
	

4. 参考链接

参考一:位移指令实现乘法、除法计算
参考二:位运算实现除法

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值