快速幂
![](https://img2024.cnblogs.com/blog/2979640/202402/2979640-20240228160136666-1495871175.png)
像这样,将指数除以2.如果不可以被2整除,将目前底数拿出一个。无论是否被2整除,都需要更新底数和指数。
c为要被取模的数(a的b次方mod c)
这个并不够优化
1 private static long fast_power(long a,long b){ 2 long res = 1; 3 while(b>0){ 4 if((b&1)>0){ 5 res = (res*a)%mod; 6 } 7 a = (a*a)%mod; 8 b>>=1; 9 } 10 return res; 11 }
1 //非递归快速幂 2 int qpow(int a, int n){ 3 int ans = 1; 4 while(n){ 5 if(n&1) //如果n的当前末位为1 6 ans *= a; //ans乘上当前的a 7 a *= a; //a自乘 8 n >>= 1; //n往右移一位 9 } 10 return ans; 11 }
这里的位运算符,>>是右移,表示把二进制数往右移一位,相当于/2;&是按位与,&1可以理解为取出二进制数的最后一位,相当于%2==1。这么一等价,是不是看出了递归和非递归的快速幂的关系了?虽然非递归快速幂因为牵扯到二进制理解起来稍微复杂一点,但基本思路其实和递归快速幂没有太大的出入。
快速幂的拓展
上面所述的都是整数的快速幂,但其实,在算 a的n次方 时,只要a的数据类型支持乘法且满足结合律,快速幂的算法都是有效的。矩阵、高精度整数,都可以照搬这个思路。下面给出一个模板:
1 //泛型的非递归快速幂 2 template <typename T> 3 T qpow(T a, ll n) 4 { 5 T ans = 1; // 赋值为乘法单位元,可能要根据构造函数修改 6 while (n) 7 { 8 if (n & 1) 9 ans = ans * a; // 这里就最好别用自乘了,不然重载完*还要重载*=,有点麻烦。 10 n >>= 1; 11 a = a * a; 12 } 13 return ans; 14 }