数学算法——快速幂

正常我们计算一个数的多少次幂都是一个一个乘,比如2的4次幂,我们就2、4、8、16,如果是2的10000次方呢,for循环一万次,如果是2的1000000000次方呢,当然进行计算的前提是对某个较大数取模,不然无法存储这么大的数,一般要求这种都是要求它的后几位,我们在计算的过程中利用乘数的取模性质,即:(a * b) % p = ((a % p) * (b % p)) % p,乘数计算后在取模等于其中每个数取模在相乘。利用这个性质,可以防止数据过大溢出,毕竟C++中long long也只能存1e18的数据(如果不考虑用数据模拟高精度乘法的话)

好了,言归正传,快速幂,怎么个快速法呢?

二进制取幂的想法是,我们将取幂的任务按照指数的 二进制表示 来分割成更小的任务。

假设我们要求a^{b},根据指数的运算法则,a^{b }=a^{2^{0}}*a^{2^{1}}\cdot \cdot \cdot *a^{2^{log 2 \left ( b \right )}}

说人话就是假如我们要求2^{7},则有等式  2^{7}=2^{2^{0}}*2^{2^{1}}*2^{2^{2}}=2^{1}*2^{2}*2^{4}

举例:

11的二进制是1011,可表示成:11=2^{0}*1+2^{1}*1+2^{2}*0+2^{3}*1

所以a^{11}=a^{2^{0}}*a^{2^{1}}*a^{2^{3}}

对于11来说,它的二进制从低往高数第三位是0,对应2^{2},我们在计算时就跳过,不把它乘进结果当中去,下面是计算思路,设res=1,存储结果

从低位往高位处理1011(右移一次,就把刚处理的低位移走

1011,处理末尾的1:计算a     res=res*a

1011,处理第2个1:计算 a^{2}     res=res*a^{2}    此时res=a^{3}

1011,处理0:对应二进制数为0,跳过 a^{4}      此时res=a^{3}

1011,处理1:计算a^{8}               res=res*a^{8}   此时res=a^{11}

下面写出快速幂的代码,计算a^{b}%p

//为防止溢出,实际使用时可以开long long
//利用乘法的取模规则,防止数据过大溢出

int fast_pow(int a,int b,int p)
{
    int res=1;
    
    while(b>0)
    {
        if(b&1)//b%2==1也可以,位运算更快一些,如果指数相应二进制数为1则乘进结果中去,否则跳过
        {
            res*=a%p;
        }
        a=a*a%p;//每次都将a的指数倍增
        b>>=1;//指数二进制数向右移一位,也可以写为b=b/2;相当于上面例子中的11
    }
    return res;
}

  既然说到了快速幂,后面我会在出一个快速乘的文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值