一、 问题描述:
计算 (a^power) % m , 其中power 是非负的大整数, a, m 为大于1 的整数。
二、 问题分析:
很显然, 由于 power 是大整数,因此,必须考虑到幂计算的溢出问题。怎么避免溢出呢? 可以通过降低幂次、逐次取模来实现。一个自然的想法是,将power 分成两个整数之和, power = n1 + n2,则 a^power = (a^n1) * (a^n2) . 通常采用二分法, n1 = n2 或 |n1-n2| = 1 。这就涉及到 (a * b) % m 的计算 。
不难证明: (a * b) % m = ((a % m) * (b % m)) % m。
证明如下: 设 a = pm + r1, b = qm + r2 , 则 r1 = a % m, r2 = b % m ,
则 (a * b) % m = (r1 * r2) % m = ((a % m) * (b % m)) % m. 证毕。
特别地,当 a = b 时, (a^2) % m = ((a % m)^2) % m ; 这是一个简单却又关键性的结论。
三、 算法设计:
算法1: 分治策略:
(1)若power 为奇数: 令 power = 2k+1, k 为非负整数 , 则
a^(2k+1) = (a^k)^2 *a ; a^(2k+1) % m = ((a^k % m)^2 % m * a) % m
(2) 若power 为偶数: 令 power = 2k, k为非负整数, 则
a^(2k) = (a^k)^2 ; a^(2k) % m = (a^k % m)^2 % m
(3) 若power == 1 : 返回 a % m ; 若 power == 0: 返回 1 % m。
据以上(1)/(2)/(3) 条, 即可设计出相应的递归求解程序。时间复杂度为T(n) = T(n/2) + C = O(logn) ,空间复杂度为 O(1), 不足之处在于有一定的递归调用开销。
算法2: 整数的二进制分解
将大整数 power 按照二进制进行分解: