最快乘法:普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦

最快乘法:普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦

提示:重要的优化算法基础知识

一定要熟练掌握这个快速乘幂的方法(a的p次幂),今后咱们要把a换成矩阵,去求矩阵A的p次幂,在那你可以看到速度的优势


题目

普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦
在这里插入图片描述


一、审题

示例:10的75次方怎么求?
在这里插入图片描述


普通求法:pow(a,p),复杂度o§

//最快乘法:普通数字a的p次幂怎么求速度最快,不用Math.pow(a,p)哦

    //如果用pow
    public static void test(){
        System.out.println(Math.pow(10, 75));
    }


    public static void main(String[] args) {
        test();
    }

系统给出来的结果

1.0E75

一般系统幂pow咋做?
循环×75次10呗,好说
在这里插入图片描述
还有递归实现
在这里插入图片描述

就说循环实现的复杂度吧,o§
你循环×这么多次,就是慢!!!

最快乘法,复杂度o(log§)

咱们这么搞

在计算机中,系统存的p就是一个二进制数
p=75=1001011
75=
在这里插入图片描述
10的75次方=
在这里插入图片描述
所以咱们拿着p=75这个数的二进制数(系统存的就是二进制呢)
从右往左(从0位开始数x),看有1的地方,×10的位x次幂
循环×就是10的p次幂

看图:
在这里插入图片描述
初始化,a=1,t=10的1次方
(1)p的0位x=1:a=a×t=1×10的1次方=10的1次方,t=t×t=10的2次方
(2)p的1位x=1:a=a×t=10的1次方=10的1次方×10的2次方,t=t×t=10的4次方
(3)p的2位x=0:a=a×t=10的1次方=10的1次方×10的2次方 ,t=t×t=10的8次方
(4)p的3位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的16次方
(5)p的4位x=0:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的32次方
(6)p的5位x=0:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的64次方
(7)p的6位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方×10的64次方 ,t=t×t=10的128次方
此时a已经是a的p=75次方了

实际上,咱们用了几次算出这个结果了?1–7就6次!!!6=log(p=75)
o(log§) 比 o§ 速度快多了吧!!!

你看懂了上面我怎么做的了吗??
实际上,就是利用二进制,当p的位x是1的地方,把10的k次方×给a
最后就得到了a的p次幂

这是不是很妙?
咱们手撕代码,你看完代码就知道这很妙

//用p的二进制数求a的p次幂
    public static double aItsPCiMi(int a, int p){
        //a=10,p=75
        // p=1001011,二进制数,从右边开始看x位
        // 初始化,a=1,t=10的1次方
        //(1)p的0位x=1:a=a×t=1×10的1次方=10的1次方,t=t×t=10的2次方
        //(2)p的1位x=1:a=a×t=10的1次方=10的1次方×10的2次方,t=t×t=10的4次方
        //(3)p的2位x=0:~~a=a×t=10的1次方=10的1次方×10的2次方~~ ,t=t×t=10的8次方
        //(4)p的3位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方 ,t=t×t=10的16次方
        //(5)p的4位x=0:~~a=a×t=10的1次方=10的1次方×10的2次方×10的8次方~~  ,t=t×t=10的32次方
        //(6)p的5位x=0:~~a=a×t=10的1次方=10的1次方×10的2次方×10的8次方~~  ,t=t×t=10的64次方
        //(7)p的6位x=1:a=a×t=10的1次方=10的1次方×10的2次方×10的8次方×10的64次方 ,t=t×t=10的128次方
        //此时a已经是a的p=75次方了

        double ans = 1;
        double tmp = a;//基数a的1次方开始

        //看p的右边开始数的位次x的1和0情况来决定
        for(; p != 0; p >>= 1){//每次p往右移位1位
            if ((p & 1) != 0){
                //p的这个位x=1的话
                ans *= tmp;
            }
            //不管p情况如何,tmp照常倍增
            tmp *= tmp;
        }

        return ans;
    }

    //如果用pow
    public static void test(){
        int a = 10;
        int p = 75;
        System.out.println(Math.pow(a, p));
        System.out.println(aItsPCiMi(a, p));
    }

就用p去控制ans是否倍×tmp,决定在x=1的地方×10的1 2 4 8 16 32 64这种次方,来计算a的p次方
每次tmp都要倍×tmp,保持10的1 2 4 8 16 32 64这种次方往上快速涨

测试结果:

1.0E75
1.0000000000000001E75

够牛吧?


总结

提示:重要经验:

1)求a的p次幂,完全可以利用二进制来优化乘幂,这样的最快乘法的速度可以加速到复杂度o(log§)
2)一定要熟练掌握这个乘幂的方法,今后咱们要把a换成矩阵,去求矩阵A的p次幂,在那你可以看到速度的优势
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冰露可乐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值