跳转至

费马小定理 & 欧拉定理

本文讨论费马小定理、欧拉定理及其扩展.这些定理解决了任意模数下任意大指数的幂的计算问题.

费马小定理

费马小定理(Fermat's little theorem)是数论中最基础的定理之一.它也是 Fermat 素性测试 的理论基础.

费马小定理

p 是素数.对于任意整数 apa,都成立 ap11(modp).

定理

p 是素数.对于任意整数 a,都成立 apa(modp).

这两个同余关系在 pa 时是等价的;而在 pa 时,ap0a(modp) 平凡地成立.因此,这两个命题是等价的.这两个命题常常都称作费马小定理.

证明一

p 是素数,且 pa.首先证明:对于 i=1,2,,p1,余数 iamodp 各不相同.反证法.如果有 1i<j<p 使得

iamodp=jamodp.(ji)a0.(modp)

但是,(ji)a 都不是 p 的倍数,这显然矛盾.

换句话说,这些余数是 {1,2,,p1} 的一个排列.因此,有

i=1p1i=i=1p1(iamodp)i=1p1ia=ap1i=1p1i.(modp)

这说明

(ap11)i=1p1i0.(modp)

也就是说,等式左侧是 p 的倍数,但是 i=1,2,,p1 都不是 p 的倍数,所以,只能有 p(ap11),亦即费马小定理成立.

证明二

注意到费马小定理的第二种表述对于所有 aN 都成立,因此,可以考虑使用数学归纳法.负整数的情形容易转化为非负整数的情形.

归纳起点为 0p0(modp),显然成立.假设它对于 aN 成立,需要证明的是,它对于 a+1 也成立.由二项式定理可知

(a+1)p=ap+(p1)ap1+(p2)ap2++(pp1)a+1.

除了首尾两项,组合数的表达式 (pk)=p!k!(pk)! 中,p 都能整除分子,而不能整除分母,因此,这些系数对于 k0,p 都是 p 的倍数.因此,有

(a+1)pap+1a+1.(modp)

其中,第二步应用了归纳假设.因此,利用数学归纳法可知,费马小定理成立.

费马小定理的逆命题并不成立.即使对于所有与 n 互素的 a,都有 an11(modn),那么,n 也未必是素数.相关讨论详见 Fermat 素性测试 一节.

欧拉定理

欧拉定理(Euler's theorem)将费马小定理推广到了一般模数的情形,但仍然要求底数与指数互素.

欧拉定理

对于整数 m>0 和整数 a,且 gcd(a,m)=1,有 aφ(m)1(modm),其中,φ()欧拉函数

证明

与费马小定理的证明一类似,仍然是取一个与 m 互质的数列,再进行操作.考虑集合

R={rN:0<r<m, gcd(r,m)=1}.

这是模 m既约剩余系.根据欧拉函数的定义可知,|R|=φ(m).类似上文,将它们乘以 a 相当于对该集合重新排列:

R={armodm:rR}.

这是因为,容易验证 gcd(ar,m)=1 且不同的 r1,r2R 对应的 ar1modmar2modm 也一定不同.因此,有

rRrrRar=aφ(m)rRr.(modm)

再次重复之前的论证,消去 rRr,就得到 aφ(m)1(modm)

对于素数 p,有 φ(p)=p1,因此,费马小定理是欧拉定理的一个特例.另外,欧拉定理中的指数 φ(m) 在一般情形下并非使得该式成立的最小指数.它可以改进到 λ(m),其中,λ()Carmichael 函数.关于相关结论的代数背景,可以参考 整数同余类的乘法群 一节.

扩展欧拉定理

扩展欧拉定理1进一步将结论推广到了底数与指数不互素的情形.由此,它彻底解决了任意模数下任意底数的幂次计算问题,将它们转化为指数小于 2φ(m) 的情形,从而可以通过 快速幂O(logφ(m)) 时间内计算.

扩展欧拉定理

对于任意正整数 m、整数 a 和非负整数 k,有

ak{akmodφ(m),gcd(a,m)=1,ak,gcd(a,m)1,k<φ(m),a(kmodφ(m))+φ(m),gcd(a,m)1,kφ(m).(modm)

第二种情形是在说,如果 k<φ(m),那么,就无需继续降幂,直接应用快速幂即可;而第三种和第一种情形的最大区别是,通过取余降幂之后,是否需要加上一项 φ(m).当然,将第一种情形合并进入第二、三种情形也是正确的.

直观理解

在严格证明定理之前,可以首先直观理解定理的含义.

fermat1

考虑余数 akmodm 随着 b 增大而变化的情况.由于余数的取值一定在区间 [0,m) 内,而 k 有无限多个.将 akmodmak+1modm 看作这些余数结点之间的有向边.那么,一定可以构成如图所示的循环.

扩展欧拉定理说明,这些循环可能是纯循环(第一种情形)或者混循环(第二、三种情形).纯循环中,没有结点存在两个前驱,而混循环中就会出现这样的情形.因此,对于一般的情况,只需要能够求出循环节的长度和进入循环节之前的长度,就可以利用这个性质进行降幂.

严格证明

本节给出扩展欧拉定理的严格证明.

证明

首先说明,存在 k0N,使得整数 am:=mgcd(ak0,m) 互素.为此,设 νp(n) 是整数 n 的质因数分解中素数 p 的幂次,那么,不妨取

k0=max{νp(m)νp(a):νp(a)>0}.

因为 m 中所有和 a 的公共素因子的幂次都已经包含在 ak0 中,所以,a 就与 m 中剩下的因子 m=mgcd(ak0,m) 互素.

进而,对 kk0 考察同余关系

bak.(modm)

由于 gcd(ak0,m)=gcd(ak,m)b,所以,将等式两侧(包括模数)同时除以 gcd(ak0,m),就有

bgcd(ak0,m)=ak0gcd(ak0,m)akk0.(modm)

此时,因为 a 与模数 m 互素,可以直接应用欧拉定理,得到

bgcd(ak0,m)ak0gcd(ak0,m)a(kk0)modφ(m).(modm)

因此,再将因子 gcd(ak0,m) 乘回去,就得到

bak0a(kk0)modφ(m)=ak0+(kk0)modφ(m).(modm)

这就得到了扩展欧拉定理的形式.式子说明,循环节的长度是 φ(m),而进入循环节之前的长度为 k0

此处得到的参数比扩展欧拉定理中的更紧,但是相对来说,这些参数的计算并不容易.可以说明,这些参数可以放宽到扩展欧拉定理中的情形.首先,利用 欧拉函数的表达式 可知,因为 mm,所以 φ(m)φ(m).也就是说,φ(m) 也是它的循环节.其次,k0 也可以放宽到 φ(m).这是因为对于所有 mN+ 和任意 pm,都有

φ(m)φ(pνp(m))=(p1)pνp(m)1pνp(m)1=(1+(p1))νp(m)11+(p1)(νp(m)1)1+(νp(m)1)=νp(m).

其中,第二行的不等式利用了二项式展开,并只保留常数项和一次项.因此,有

k0max{νp(m):pP}φ(m).

这就完全证明了所述结论.

例题

本节通过一道例题展示扩展欧拉定理的一个经典应用——计算任意模数下的幂塔.幂塔(power tower)指形如 A(B(C(D))) 的式子,其中, 是 Knuth 箭头记号,而 A,B,C,D, 是一系列非负整数.

Library Checker - Tetration Mod

T 组测试.每组测试中,给定 A,B,M,求 (A↑↑B)modM.其中,A↑↑B 表示由 BA 组成的幂塔.或者,形式化地,定义

A↑↑B={1,B=0,A(A↑↑(B1)),B>0.

规定 00=1

解答

利用 A↑↑B 的定义,递归计算即可.要计算 (A↑↑B)modM,只需要应用扩展欧拉定理,计算 (A↑↑(B1))modφ(M).由于 φ(φ(n))n/2 对所有 n2 都成立,所以,递归过程一定在 O(logM) 步内完成.由于需要应用扩展欧拉定理,所以需要区分当前的计算结果是否严格小于当前模数.为此,只需要在取余的时候多判断一步即可.另外,需要注意边界情况的处理.

参考代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

// Calculate Euler's totient for n.
int phi(int n) {
  int res = n;
  for (int i = 2; i * i <= n; ++i) {
    if (n % i == 0) {
      res = res / i * (i - 1);
      while (n % i == 0) n /= i;
    }
  }
  if (n > 1) res = res / n * (n - 1);
  return res;
}

// Find remainder as in the exponent of extended Euler theorem.
int mod(long long v, int m) { return v >= m ? v % m + m : v; }

// Modular power.
int pow(int a, int b, int m) {
  long long res = 1, po = a;
  for (; b; b >>= 1) {
    if (b & 1) res = mod(res * po, m);
    po = mod(po * po, m);
  }
  return res;
}

// Modular tetration.
int tetra(int a, int b, int m) {
  if (a == 0) return !(b & 1);
  if (b == 0 || m == 1) return 1;
  if (b == 1) return mod(a, m);
  return pow(a, tetra(a, b - 1, phi(m)), m);
}

int main() {
  int t;
  std::cin >> t;
  for (; t; --t) {
    int a, b, m;
    std::cin >> a >> b >> m;
    std::cout << (tetra(a, b, m) % m) << std::endl;
  }
}
取模技巧正确性证明

本实现利用

rm(v)={vmodm,if v<m,vmodm+m,if vm

代替取模,相当于同时记录了余数信息 vmodm 和越界信息 vm.扩展欧拉定理只能说明,当指数的余数信息和越界信息都正确时,取幂能够得到正确的余数信息;但是,越界信息的正确性无法保证.例如,在计算 r6(24) 时,指数需要对 φ(6)=2 取模,而 r2(4)=2(即余数为 0 且越界),进行取幂后将得到 r6(22)=4;与正确答案 r6(24)=10 相比,模 6 的余数正确,但是越界信息丢失.但可以证明,尽管越界信息可能丢失,余数信息却总是正确的.因此,基于这一取模技巧的取幂算法也总是正确的.

考虑算法的迭代过程.假设从最内层开始向外层函数回溯,第一次越界信息错误发生在计算 rm(ak) 时.k<φ(m) 时指数精确,不会出错,故设 kφ(m);此时 kkmodφ(m)+φ(m),即取模只会低估指数,越界信息不会凭空产生,出错的唯一可能是本应记录越界而实际未记录,即

akmodφ(m)+φ(m)<mak.

该不等式只能在 a2 时成立,所以左侧表达式不小于 2φ(m).但是,2φ(m)<m 只会发生在 m=6 时.2代入上式,就得到 akmod2+2<6ak.左侧表达式中,若 k 是偶数,则指数是 2,有 a=2k4;若 k 是奇数,则指数是 3,无解.综上,丢失越界信息只发生在 m=6, a=2k4 是偶数时.

下面说明,这一情形下丢失越界信息并不影响后续计算.只考虑 ai2 的非平凡情形(ai1 时幂值不超过 1,不会越界).内层模数为 6,故回溯一层后的模数 m1 满足 φ(m1)=6,只能是 7,9,14,18 之一.回溯到该层时,需要计算 rm1(a1k1),而 k1 本应为 10,实际为 4.但对所有 a1 和这些 m1,都有 a14a110(modm1).为说明这一点,注意到前文扩展欧拉定理的 证明 中已经得到:对任何 am,幂次余数 akmodm 进入循环节之前的长度 k0 都不超过 ν+(m):=max{νp(m):pm},且循环节长度整除 φ(m).而 ν+(m1)2,故 k1=4 已进入循环节,且它与 10 相差 φ(m1)=6,亦即上式总成立.所以余数信息正确.再看越界信息.由于内层真实值为 2k16>10,故 a12ka110m1,本层总应该标记越界.但本层只会返回 a14 是否越界;唯一出错的可能是 a14<m1,即只能有 a1=2, m1=18.其余情形的越界信息已正确标记,继续回溯自然正确.而 a1=2, m1=18 时,本应返回 34,实际返回 16,需再回溯一层,此时 m2 只能是 19,27,38,54 之一.此时总有 ν+(m2)3<163416=φ(m2),余数信息正确;且 a216m2 恒成立,越界信息也正确.所以此时结果正确,后续回溯也必然正确.

由于各层模数严格递减,m=6 至多出现一次.综上,利用该取模技巧计算多层幂次时,每一层的余数信息都是正确的,至多只有两层的越界信息是错误的.注意,证明中没有假定各层取幂的底数相同,故结论对不同底数的情形也成立.

习题

参考资料与注释


  1. 这一名字主要出现在算法竞赛圈中,而并非该结论的通用名称. 

  2. 根据 Kendall, R. and Osborn, R. (1965) Two Simple Lower Bounds for the Euler ϕ-Function. Texas Journal of Science, 17, 324-326 一文,对于 m>6 总有 φ(m)m.直接计算可知,对于 m16,总有 mlog2m.因此,不等式 φ(m)log2mm16 都成立.其余可逐一验证.