正常我们计算一个数的多少次幂都是一个一个乘,比如2的4次幂,我们就2、4、8、16,如果是2的10000次方呢,for循环一万次,如果是2的1000000000次方呢,当然进行计算的前提是对某个较大数取模,不然无法存储这么大的数,一般要求这种都是要求它的后几位,我们在计算的过程中利用乘数的取模性质,即:(a * b) % p = ((a % p) * (b % p)) % p,乘数计算后在取模等于其中每个数取模在相乘。利用这个性质,可以防止数据过大溢出,毕竟C++中long long也只能存1e18的数据(如果不考虑用数据模拟高精度乘法的话)
好了,言归正传,快速幂,怎么个快速法呢?
二进制取幂的想法是,我们将取幂的任务按照指数的 二进制表示 来分割成更小的任务。
假设我们要求,根据指数的运算法则,
说人话就是假如我们要求,则有等式 =
举例:
11的二进制是1011,可表示成:11=
所以
对于11来说,它的二进制从低往高数第三位是0,对应,我们在计算时就跳过,不把它乘进结果当中去,下面是计算思路,设res=1,存储结果
从低位往高位处理1011(右移一次,就把刚处理的低位移走)
1011,处理末尾的1:计算a res=res*a
1011,处理第2个1:计算 res=res* 此时res=
1011,处理0:对应二进制数为0,跳过 此时res=
1011,处理1:计算 res=res* 此时res=
下面写出快速幂的代码,计算%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;
}
既然说到了快速幂,后面我会在出一个快速乘的文章