Java 实现快速乘 快速幂算法 从比较容易理解的快速乘过渡到快速幂

快速乘快速幂本质原理

  1. 在计算机中 1和1相加 以及 123456789和123456789相加,两个计算速度差不多,因为不管是1还是123456789,在int中都是占4个字节,它们的所占的位数都一样,所以影响计算机计算速度的就是加法的次数
  2. 还是 1和1 以及 123456789和123456789,不过此时是相乘,由于计算机的乘法实际上转化为加法计算,所以第二个相加次数会很大,所以这时候就需要用到快速乘算法
  3. 如果 101 * 33,计算机可以选择一种比较简单的方式就是 33 个 101 相加,那样只有32次加法,如果是101 个 33 相加那样就会有 100 次加法
  4. 如果用快速乘呢,那么会就会利用累积效应,第一次计算两个101相加得到202,第二次计算两个202相加得到404,依此类推并记录下每次相加的值,可以得到数组[101,202,404,808,1616,3232],我们可以发现仅仅通过5次加法,我们就可以得到这样一个数组,然后101 * 33 = 3333 = 3232 + 101(这里等号是数学的等号),所以101 * 33 可以拆成 3232 + 101,那样我们可以从上面数组找到这两个数,然后只加1次就可以得出来了,所以只用了6次加法就计算出了 101 * 33,而普通计算机需要32次才行
  5. 上面的6次加法可以优化成5次,我们可以在生成数组的同时把值加上去,设置连数组都不必要,但是为了容易理解我们还是生成数组好点
  6. 快速幂也一样,如果是101的33次方,则第一次计算101 * 101得到 101 ^ 2, 第二次计算101 ^ 2 * 101 ^ 2得到 101 ^ 4,依此类推,那么我们生成的数组是[101 ^ 1 , 101 ^ 2 ,101 ^ 4 , 101 ^ 8 ,101 ^ 16, 101 ^ 32],而我们的 101 ^ 33 = 101 ^ 32 * 101,所以原先的33次乘法,变成了6次乘法
  7. 但是快速幂中到最后如101 ^ 16 * 101 ^ 16, 这两个乘法仍然会变成很多次加法,如果我们在快速幂中再使用快速乘法的优化,那样就能加幂运算变成很少次的加法了

算法实现

快速乘

  1. 我们先获取a和b中最小的,因为这样相加次数最小
  2. 第一个for循环是为了构造上面说的数组
  3. 然后后面的while循环是遍历该数组,将数组中的某些值相加求出我们的目的值
  4. 1 << i ,是左移,1<< 1 等于2,1 << 2 等于4,其实只是为了快速求2的多少次方而已
public class FastMultiplication {
    public static void main(String[] args) {
        int i = new FastMultiplication().fastMultiplication(4, 4);
        System.out.println(i);
    }

    public int fastMultiplication(int a, int b) {
        if (a == 0 || b == 0) return 0;
        int min = Math.min(a, b);
        int max = Math.max(a, b);
        int[] count = new int[32];
        count[0] = max;
        for (int i = 1; i < 32; i++) {
            count[i] = (count[i-1] * 2);
            if ((1 << (i+1)) > max) {
                break;
            }
        }
        System.out.println(Arrays.toString(count));
        int result = 0;
        while (min > 0) {
            for (int i = 30; i >= 0 ; i--) {
                if (min >= (1 << i)) {
                    min -= (1 << i);
                    result += count[i];
                }
            }
        }
        return result;
    }
}

快速幂

  1. 前面三个if是为了应对特殊情况,如果num ^ exponentiation 的 exponentiation为0,则返回值1,exponentiation为1,则返回值 num
  2. 第一个for循环也是为了构造上面所说的数组
  3. while循环,从数组右边往左找,找到对应的值相乘就得到我们要的值了
public class FastExponentiation {
    public static void main(String[] args) {
        int i = new FastExponentiation().fastExponentiation(9, 1);
        System.out.println(i);
    }

    public int fastExponentiation(int num, int exponentiation) {
        if (exponentiation == 0) return 1;
        if (num == 0) return 0;
        if (exponentiation == 1) return num;
        int[] count = new int[32];
        count[0] = num;
        for (int i = 1; i < 32; i++) {
            count[i] = (count[i-1] * count[i-1]);
            if ((1 << (i+1)) > exponentiation) {
                break;
            }
        }
        System.out.println(Arrays.toString(count));
        int result = 1;
        while (exponentiation > 0) {
            for (int i = 30; i >= 0 ; i--) {
                if (exponentiation >= (1 << i)) {
                    exponentiation -= (1 << i);
                    result *= count[i];
                }
            }
        }
        return result;
    }
}

快速幂(改进)

  1. 和上面快速幂差不多,只有两处改动
  2. count[i] = (count[i-1] * count[i-1]) 替换成 count[i] = fastMultiplication(count[i-1], count[i-1])
  3. 将 result *= count[i] 替换成 result = fastMultiplication(result, count[i])
public class FastExponentiationOptimization {
    public static void main(String[] args) {
        int i = new FastExponentiationOptimization().fastExponentiation(4, 10);
        System.out.println(i);
    }

    public int fastExponentiation(int num, int exponentiation) {
        if (exponentiation == 0) return 1;
        if (num == 0) return 0;
        if (exponentiation == 1) return num;
        int[] count = new int[32];
        count[0] = num;
        for (int i = 1; i < 32; i++) {
//            count[i] = (count[i-1] * count[i-1]);
            count[i] = fastMultiplication(count[i-1], count[i-1]);
            if ((1 << (i+1)) > exponentiation) {
                break;
            }
        }
        System.out.println("fastExponentiation:"+Arrays.toString(count));
        int result = 1;
        while (exponentiation > 0) {
            for (int i = 30; i >= 0 ; i--) {
                if (exponentiation >= (1 << i)) {
                    exponentiation -= (1 << i);
//                    result *= count[i];
                    result = fastMultiplication(result, count[i]);
                }
            }
        }
        return result;
    }

    public int fastMultiplication(int a, int b) {
        if (a == 0 || b == 0) return 0;
        int min = Math.min(a, b);
        int max = Math.max(a, b);
        int[] count = new int[32];
        count[0] = max;
        for (int i = 1; i < 32; i++) {
            count[i] = (count[i-1] * 2);
            if ((1 << (i+1)) > max) {
                break;
            }
        }
        System.out.println("fastMultiplication:"+Arrays.toString(count));
        int result = 0;
        while (min > 0) {
            for (int i = 30; i >= 0 ; i--) {
                if (min >= (1 << i)) {
                    min -= (1 << i);
                    result += count[i];
                }
            }
        }
        return result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lolxxs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值