我想找到一个快速算法来评估如下表达式,其中 P 是素数。
A ^ B ^ C ^ D ^ E mod P
示例:
(9 ^ (3 ^ (15 ^ (3 ^ 15)))) mod 65537 = 16134
问题是中间结果可能会变得太大而无法处理。
答案 0 :(得分:13)
基本上,对于给定的a^T mod m
,a
和一个非常庞大的术语m
,问题会减少到计算T
。但是,我们能够使用给定模数T mod n
评估n
比T
快得多。所以我们问:“是否有整数n
,这样a^(T mod n) mod m = a^T mod m
?”
现在如果a
和m
是互质的,我们知道n = phi(m)
根据Euler's theorem符合我们的条件:
a^T (mod m)
= a^((T mod phi(m)) + k * phi(m)) (mod m) (for some k)
= a^(T mod phi(m)) * a^(k * phi(m)) (mod m)
= a^(T mod phi(m)) * (a^phi(m))^k (mod m)
= a^(T mod phi(m)) * 1^k (mod m)
= a^(T mod phi(m)) (mod m)
如果我们可以计算phi(m)
(例如在O(m^(1/2))
中很容易做到,或者如果我们知道m
的素数分解),我们就会将问题简化为计算T mod phi(m)
1}}和一个简单的modular exponentiation。
如果a
和m
不是互质的,该怎么办?情况不像以前那么令人愉快,因为对于所有n
,可能没有有效a^T mod m = a^(T mod n) mod m
属性T
。但是,我们可以证明a^k mod m
的序列k = 0, 1, 2, ...
在某个点之后进入一个循环,即存在x
和C
与x, C < m
,这样所有a^y = a^(y + C)
都是y >= x
。
示例:对于a = 2, m = 12
,我们得到序列2^0, 2^1, ... = 1, 2, 4, 8, 4, 8, ... (mod 12)
。我们可以看到包含参数x = 2
和C = 2
的循环。
通过计算序列元素a^0, a^1, ...
,我们可以通过暴力找到周期长度,直到我们找到两个带X < Y
的索引a^X = a^Y
。现在我们设置x = X
和C = Y - X
。这给了我们一个每次递归O(m)
指数的算法。
如果我们想做得更好怎么办?感谢Math Exchange的Jyrki Lahtonen提供the essentials for the following algorithm!
让我们评估序列d_k = gcd(a^k, m)
,直到我们找到x
d_x = d_{x+1}
。这将最多需要log(m)
个GCD计算,因为x
受m
的素数因子分解中的最高指数限制。让C = phi(m / d_x)
。所有a^{k + C} = a^k
都We can now prove that k >= x
,因此我们在O(m^(1/2))
时间内找到了周期参数。
我们假设我们找到了x
和C
,现在想要计算a^T mod m
。
如果T < x
,使用简单的模幂运算执行任务是微不足道的。否则,我们有T >= x
,因此可以使用循环:
a^T (mod m)
= a^(x + ((T - x) mod C)) (mod m)
= a^(x + (-x mod C) + (T mod C) + k*C) (mod m) (for some k)
= a^(x + (-x mod C) + k*C) * a^(T mod C) (mod m)
= a^(x + (-x mod C)) * a^(T mod C) (mod m)
同样,我们将问题简化为相同形式的子问题(“compute T mod C
”)和两个简单的模幂运算。
由于模数在每次迭代中减少了至少1,因此对于此算法的运行时间,我们得到O(P^(1/2) * min (P, n))
的非常弱的界限,其中n
是堆栈的高度。在实践中,我们应该好多了,因为模量预计会呈指数下降。当然这个论点有点手持波动,也许一些更具数学倾向的人可以改进它。
有一些边缘情况需要考虑,实际上让您的生活更轻松:如果m = 1
(在这种情况下结果为0)或a
是倍数的倍数,您可以立即停止m
(在这种情况下,结果也是0)。
编辑:可以证明x = C = phi(m)
有效,因此作为快速而肮脏的解决方案,我们可以使用公式
a^T = a^(phi(m) + T mod phi(m)) (mod m)
代表T >= phi(m)
甚至T >= log_2(m)
。