WTF zk教程第9讲:欧拉函数
给定一个整数 n,小于等于 n 的正整数中有多少和 n 互质的数呢?这一讲,我们将研究这个问题,知识点包括单元集和欧拉函数。
1. 单元集
如果 x∈Zn 是可逆的(即存在乘法逆元),那么我们称 x 为 Zn 的单元。 Zn 所有单元的组成的集合被称为单元集(Unit set),记为 Zn∗。
通过之前的学习,我们知道 x∈Zn 可逆的充要条件是 x 与 n 互质。因此 Zn∗ 中的元素就是 [1,...,n−1] 中与 n 互质的正整数。在同余理论中,这个集合也被称为模 N 的互质同余类。
举个几个例子:
Z2∗={1}
Z3∗={1,2}
Z5∗={1,2,3,4}
Z8∗={1,3,5,7}
Z9∗={1,2,4,5,7,8}
Z15∗={1,2,4,7,8,11,13,14}
2. 欧拉函数
欧拉函数为 ϕ(n)=∣Zn∗∣,为单元集 Zn∗ 中元素的个数。也就是 [1,...,n−1] 中与 n 互质的整数的个数。另外,我们特别定义 ϕ(1)=1。
举个几个例子: ϕ(2)=1, ϕ(3)=2, ϕ(5)=4, ϕ(8)=4, ϕ(9)=6, ϕ(15)=8。
2.1 欧拉函数的性质
欧拉函数有一些神奇的性质,让我们很容易计算 Zn∗ 中元素的个数。前两条性质是当 n 为质数时的性质。第三条是欧拉函数的积性,当 n 为合数时,我们可以将它转换为几个质数的欧拉函数的乘积,方便计算。
1. 对于质数 p,有 ϕ(p)=p−1
举几个例子: ϕ(2)=1, ϕ(3)=2, ϕ(13)=12。
点我展开证明👀
由于 p 为质数,所以任意 x∈Zp 都与 p 互质,也就是 [1,...,p−1],共 p−1 个元素。
2. 对于质数 p, 正整数 k,有 ϕ(pk)=pk−pk−1。
举几个例子:
ϕ(8)=ϕ(23)=23−22=4 ϕ(9)=ϕ(32)=32−31=6 点我展开证明👀
在 [1,...,pk] 中共有 pk 个元素。由于 p 为质数,因此其中仅有 p 的倍数 [p,2p,3p,...,pk−p,pk] 可以被 p 整除,不与 p 互质。所以,每 p 个数中,仅有 1 个数不与 p 互质,这样的数总共有 pk/p=pk−1 个。因此,与 p 互质的数共有 pk−pk−1 个, ϕ(pk)=pk−pk−1。
3. 若 m 和 n 互质,即 gcd(m,n)=1,有 ϕ(mn)=ϕ(m)ϕ(n)
举几个例子:
ϕ(15)=ϕ(3)×ϕ(5)=2×4=8 ϕ(18)=ϕ(2)×ϕ(32)=1×(32−31)=6 点我展开证明👀
我们要证明 Zmn∗ 和 Zm∗×Zn∗ 存在双射关系,即 Zmn∗ 和 Zm∗×Zn∗ 的元素一一对应,那么他们的元素个数就是相等的。而左边元素的个数是 ϕ(mn),右边的是 ϕ(m)ϕ(n),因此 ϕ(mn)=ϕ(m)ϕ(n)。
我们建立一个映射关系 f:Zmn∗→Zm∗×Zn∗,它对模 m 和模 n 的余数 a,b 都是唯一确定的,所以这个映射是定义明确的。
满射: 由于 m 和 n 互质,通过中国剩余定理,我们知道对于任意的 (a,b)∈Zm∗×Zn∗,考虑同余方程系统:
x≡a(modm)
x≡b(modn)
,有唯一解 x。因此,对于 Zm∗×Zn∗ 中的任意元素,都存在一个 x 使得 f(x)=(a,b)。因此 f 是满射,也就是说映射覆盖了整个集合 Zm∗×Zn∗。
单射: 假设有两个不同的元素 x1 和 x2。就有 f(x1)=f(x2),也就是
(x1modm,x1modn)=(x2modm,x2modn)
这意味着 x1≡x2(modm) 且 x1≡x2(modn)。因此有 x1≡x2(modmn)。因此,x1 和 x2 在模 mn 下是相等的,证明了 f 是单射。
由于 f 既是满射又是单射,则 f 是双射。因此 Zmn∗ 和 Zm∗×Zn∗ 存在双射关系,它们的元素一一对应,有 ϕ(mn)=ϕ(m)ϕ(n)。
根据以上三条性质,我们可以把一个大数的欧拉函数转化成为它的因式分解后欧拉函数的乘积:若 n 有质数分解 p1k1p2k2...prkr(其中各 pi 为互异的质因子, ki≥1 为质因子的次数),则欧拉函数在该处的值为:
ϕ(n)=p1k1−1p2k2−1...prkr−1(p1−1)(p2−1)...(pr−1) 也可以等价的写为:
ϕ(n)=n(1−1/p1)(1−1/p2)...(1−1/pr) 总之:由于任意大于 1 的正整数都可以分解成若干质数的乘积,不妨设 N=∏i=1lpiαi ,则 φ(N)=∏i=1lpiαi−1(pi−1) 。特别地,如果 N=pα ,则 φ(N)=pα−1(p−1) 。更为特殊地,如果 N=p ,则 φ(N)=p−1 。
2.2 代码实现:
我们可以用python实现欧拉函数。代码包含两个函数,prime_factors()
将 n 质数分解,euler_phi
利用公式计算 ϕ(n):
def prime_factors(n):
factors = []
p = 2
while p * p <= n:
while n % p == 0:
factors.append(p)
n //= p
p += 1
if n > 1:
factors.append(n)
return factors
def euler_phi(n):
result = n
factors = prime_factors(n)
for p in set(factors):
result -= result // p
return result
n = 15
print(f"欧拉函数 phi({n}): {euler_phi(n)}")
这一讲,我们介绍了单元集和欧拉函数,它们可以用来计算小于等于 n 的正整数中和 n 互质的数量。我们将在下一讲介绍欧拉定理,会用到欧拉函数。