算法通关村 —— 位运算实现加减乘除

位运算实现加减乘除

在计算机中,位运算的效率比单纯加减乘除的效率更高,因此在高性能软件的源码中大量应用。而且计算机里各种运算本质上都是位运算,所以也是高频考题,让我们一起学习下面几个问题。

一 位运算实现加法

给你两个整数 a 和 b, 不使用 运算符 + 和 -,计算并返回两整数之和。

示例:输入:a = 1, b = 2         输出:3

题目要求不使用 + 和 - ,所以我们就得使用位运算啦,两个二进制位相加有以下几种情况:

[1] 0 + 0 = 0
[2] 0 + 1 = 1
[3] 1 + 0 = 1
[4] 1 + 1 = 1

由上可发现,相同为0,不同为1,这不就是异或运算a⊕b嘛! 所以我们可以利用异或运算来计算

但是还需考虑进位问题,我们发现,只有a和b都是1才会进位,而且进位只能是1。需要a和b同时为1,这不就是a & b=1吗? 然后进位我们只需手动向左移一位就好,也就是(a & b) << 1.

所以有以下两条结论:

⚪ 不进位部分:用a⊕b直接计算

⚪ 是否进位,以及进位值使用(a & b) << 1即可


具体实现代码如下:

class Solution {
    public int getSum(int a, int b) {
        while(b != 0){
            // 标志是否进位1
            int sign = (a & b) << 1;
            // a 与 b做异或运算得到无进位加法结果
            a = a^b;
            // b赋值位进位结果,若不为0,说明还需进位,供下此与a做进位计算
            b = sign;
        }
        return a;
    }
}

二 乘法实现

不适用 * 运算符,实现两个正整数的相乘,可以使用加号、减号、位移,但要吝啬一些。

由于不让用 * 来计算,所以我们可以将一个作为循环的参数,对另一个进行累加,但这样效率太低,所以我们还是要考虑进行位运算。

首先,取两个整数中的最小值当作乘数(原因是选最小值作为乘数,可以计算比较少),将其拆分成2的幂的和,即min = a_0 * 2 ^ 0 + a_1 * 2 ^ 1 + …… + a_i * 2 ^ i + ……,其中a_i取0或者1.其实就是用二进制去表示min值,比如12用二进制表示为1100,即1000 + 0100.

例如:13 * 12 = 13 * ( 8 + 4) = (13 << 3) + (13 << 2)

上面的乘法需要进行5次左移,存在重复的位移计算,所以可以进一步简化:

假设我们存放的结果为ans,定义临时变量tmp

tmp = 13 << 2 = 52 计算之后,可以先让ans = 52,

然后让tmp继续左移一次,即tmp = 52 << 1 = 104, 此时再让ans = ans + tmp

这样只要执行三次移位和一次假发,效率就高很多了,实现代码如下:

class Solution {
    public int multiply(int A, int B) {
        // 分别取得最大值和最小值
        int max = Math.max(A, B);
        int min = Math.min(A, B);
        int ans = 0; // 存放结果值
        // 对小的值进行移位直到为0说明乘以该数完毕
        for (int i = 0; min != 0; i++){
            // 当min 位为1时才更新ans,否则一直更新max,这样就只做一次加法
            if ((min & 1) == 1) ans += max; // 加上最后一个max
            min >>= 1;
            max += max; // 大的数一直变成2倍
        }
        return ans;
    }
}

你可能感兴趣的:(算法)