无极之地
WUJI
无极之地。记录所思所见,慢慢写下去。
欧拉函数 φ(n):定义、积性与公式
世界时钟 北京 --:--:-- 东京 --:--:-- UTC --:--:-- 伦敦 --:--:-- 纽约 --:--:-- 模 n n n 把整数切成 n n n 个同余类。完全剩余系是把每一类各挑一个代表;简化剩余系再加一道筛:只留和 n n n 互素的那些类。两套对象看起来只是「选代表」,真正管的却是后面几乎所有乘法论证:平移会不会丢类、互素倍乘会不会重排、以及为什么可逆元恰好有 φ ( n ) \varphi(n) φ ( n ) 个。下面把定义、两条定理和欧拉函数放在一起,手算和代码对得上即可。
完全剩余系
固定正整数 n n n 。一组整数
a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a
1
,
a 2
,
…
,
a n
叫做模 n n n 的完全剩余系 ,如果它们两两模 n n n 不同余。换句话说,这 n n n 个数恰好落在 n n n 个不同的同余类里,每一类一个。
{ 0 , 1 , 2 , … , n − 1 } , { 1 , 2 , … , n } \{0,1,2,\dots,n-1\},\qquad \{1,2,\dots,n\} { 0 , 1 , 2 , … , n − 1 } , { 1 , 2 , … , n } 前者常叫最小非负完全剩余系。奇数模还可以取对称的一组:
{ − n − 1 2 , … , − 1 , 0 , 1 , … , n − 1 2 } \left\{-\frac{n-1}{2},\dots,-1,0,1,\dots,\frac{n-1}{2}\right\} { − 2 n − 1 , … , − 1 , 0 , 1 , … , 判定不必真的列出余数表。只要确认两件事:一共 n n n 个数,并且任意两个差不被 n n n 整除。个数对了、两两不同余,就自动覆盖全部同余类——因为同余类总共只有 n n n 个,装进 n n n 个互异的盒子里,只能是每盒恰好一个。
等价说法还有两种,用起来更方便。其一:把每个 a i a_i a i 换成 a i m o d n a_i\bmod n a i mod n ,得到的恰好是 { 0 , 1 , … , n − 1 } \{0,1,\dots,n-1\} { 的一个排列。其二:任意整数 都和其中恰好一个 同余。三种表述一样,证明里常在「两两不同余」和「覆盖全部」之间切换。
代表可以取得很野。{ 12 , − 3 , 22 , 7 } \{12,-3,22,7\} { 12 , − 3 , 22 , 7 } 模 4 4 4 分别是 0 , 1 , 2 , 3 0,1,2,3 0 , 1 , 2 , 3 ,因此也是完全剩余系。关键从来不是数本身小不小,而是它们落在哪些类里。
简化剩余系 完全剩余系里,有的代表和 n n n 互素,有的不互素。把不互素的丢掉,剩下的叫做模 n n n 的简化剩余系 (也叫既约剩余系)。
r 1 , r 2 , … , r k r_1,r_2,\dots,r_k r 1 , r 2 , … , r k
每个 r i r_i r i 都满足 gcd ( r i , n ) = 1 \gcd(r_i,n)=1 g cd( r i , n ) = 1 ;
它们两两模 n n n 不同余;
个数 恰好等于与 互素的同余类个数。
这个个数记作 φ ( n ) \varphi(n) φ ( n ) ,即欧拉函数。于是任何简化剩余系都恰好有 φ ( n ) \varphi(n) φ ( n ) 个元素。标准取法是
{ a : 1 ≤ a ≤ n , gcd ( a , n ) = 1 } \{a : 1\le a\le n,\ \gcd(a,n)=1\} { a : 1 ≤ a ≤ n , g cd( a , n ) = 1 } 例如 n = 8 n=8 n = 8 时,φ ( 8 ) = 4 \varphi(8)=4 φ ( 8 ) = 4 ,简化剩余系可以取 { 1 , 3 , 5 , 7 } \{1,3,5,7\} { 1 , 3 , 5 , 7 } 。n = 9 n=9 n = 9 时, ,可以取 。注意 永远不在简化剩余系里——除非 这种平凡情形。 时 ,零类没有乘法逆。
同一套简化剩余系可以换代表。{ 9 , 11 , 13 , 15 } \{9,11,13,15\} { 9 , 11 , 13 , 15 } 模 8 8 8 仍是 { 1 , 3 , 5 , 7 } \{1,3,5,7\} { 1 , 3 , 5 , 7 } ,所以也是简化剩余系。换代表的合法操作是对单个 元素加上 n n n 的倍数;对整组加同一个与 n n 无关的常数,互素性一般会坏掉。下一节平移定理会把这件事说清楚。
简化剩余系对应的是环 Z / n Z \mathbb{Z}/n\mathbb{Z} Z / n Z 里的乘法可逆元,也就是单位群 ( Z / n Z ) × (\mathbb{Z}/n\mathbb{Z})^\times ( Z / n Z ) × 。后面倍乘定理会用到这一点:和 n n n 互素,等价于模 n n n 有逆元。完全剩余系描述加法上的「满席」,简化剩余系描述乘法上的「可逆席」。
平移之后仍是完全剩余系 定理。 设 a 1 , … , a n a_1,\dots,a_n a 1 , … , a n 是模 n n n 的完全剩余系,b b b 是任意整数。则
a 1 + b , a 2 + b , … , a n + b a_1+b,\ a_2+b,\ \dots,\ a_n+b a 1 + b , a 2 + b , … , a a i + b ≡ a j + b ( m o d n ) a_i+b\equiv a_j+b\pmod n a i + b ≡ a j + b ( mod n ) 两边减 b b b ,得到 a i ≡ a j ( m o d n ) a_i\equiv a_j\pmod n a i ≡ a j ( mod n ) 。原来是完全剩余系,故 i = j i=j 。于是平移后仍然两两不同余,结论成立。
直观说法是:每个同余类同时加 b b b ,只是把标签转了一圈,没有两堆并成一堆,也没有空出一堆。映射 x ↦ x + b x\mapsto x+b x ↦ x + b 在模 n n n 的同余类上是双射,所以把一套完全代表送成另一套完全代表。
也可以先取模再看。设 a i ≡ i − 1 ( m o d n ) a_i\equiv i-1\pmod n a i ≡ i − 1 ( mod n ) 是最小非负那一组,则 a i + b ≡ ( i − 1 + b ) m o d n a_i+b\equiv (i-1+b)\bmod n a ,不过是把 循环移位,当然还是完全剩余系。一般的完全剩余系只是这组的重排,结论一样。
平移不 保简化剩余系。{ 1 , 3 , 5 , 7 } \{1,3,5,7\} { 1 , 3 , 5 , 7 } 是模 8 8 8 的简化剩余系,每个加 1 1 1 变成 { 2 , 4 , 6 , 8 } \{2,4,6,8\} { 2 , 4 , 6 , 8 } ,四个数都和 8 8 8 不互素。加一个常数会改变「是否与模互素」这件事,所以简化剩余系没有一般的平移定理。只有极特殊的 偶尔还能留下 个互素类,不能当定理用。
倍乘之后何时仍是剩余系 定理。 设 a 1 , … , a n a_1,\dots,a_n a 1 , … , a n 是模 n n n 的完全剩余系。若 gcd ( c , n ) = 1 \gcd(c,n)=1 g cd( c , n ) ,则
c a 1 , c a 2 , … , c a n ca_1,\ ca_2,\ \dots,\ ca_n c a 1 , c a 2 , … , c a n 证明。 个数仍是 n n n 。若 c a i ≡ c a j ( m o d n ) ca_i\equiv ca_j\pmod n c a i ≡ c a j ( mod n ) ,则 整除 。因为 , 与 没有公共素因子,故 必须整除 ,即 。原来两两不同余,所以 。
条件 gcd ( c , n ) = 1 \gcd(c,n)=1 g cd( c , n ) = 1 不能少。若 d = gcd ( c , n ) > 1 d=\gcd(c,n)>1 d = g cd( c , n ) > 1 ,则每个 c a i ca_i c a 都是 的倍数,倍乘后的数只能落在模 下 的倍数那几类里,覆盖不满 类,当然不是完全剩余系。更定量地说,像的个数是 :同一个余数会重复 次。模 乘 只剩 四类,每类出现两次,就是这个计数。
证明里真正用到的是「c c c 可以约掉」。n ∣ c ( a i − a j ) n\mid c(a_i-a_j) n ∣ c ( a i − a j ) 且 gcd ( c , n ) = 1 \gcd(c,n)=1 ,于是 。若 与 有公约数,这一步就不成立, 撞车也无法回溯到 撞车。
定理。 设 r 1 , … , r φ ( n ) r_1,\dots,r_{\varphi(n)} r 1 , … , r φ ( n ) 是模 n n n 的简化剩余系。若 gcd ( c , n ) = 1 \gcd(c,n)=1 ,则
c r 1 , c r 2 , … , c r φ ( n ) cr_1,\ cr_2,\ \dots,\ cr_{\varphi(n)} c r 1 , c r 2 , … , c r φ ( n ) 证明。 先看互素:gcd ( c , n ) = 1 \gcd(c,n)=1 g cd( c , n ) = 1 且 gcd ( r i , n ) = 1 \gcd(r_i,n)=1 g cd( r i , n ) = 1 ,故 gcd ( c r i , n ) = 1 \gcd(cr_i,n)=1 。再看两两不同余:若 ,同样用 推出 ,从而 。个数仍是 ,三件事齐了。
也可以从可逆元来看。c c c 模 n n n 可逆,乘 c c c 是 ( Z / n Z ) × (\mathbb{Z}/n\mathbb{Z})^\times ( Z / n Z ) × 上的双射,只是把简化剩余系重新排列。
两条倍乘定理合在一起,常用推论是:对任意与 n n n 互素的 c c c ,以及任意完全(或简化)剩余系 { a i } \{a_i\} { a i } ,集合 { c a i m o d n } \{ca_i\bmod n\} { c a i 只是原集合的一个置换。
φ ( n ) \varphi(n) φ ( n ) 可以就定义为「模 n n n 的简化剩余系里有几个数」。标准公式
φ ( n ) = n ∏ p ∣ n ( 1 − 1 p ) \varphi(n)=n\prod_{p\mid n}\left(1-\frac{1}{p}\right) φ ( n ) = n p ∣ n ∏ ( 1 − p 1 ) 说的是同一件事:先有 n n n 个同余类,再按素因子把不互素的类剔掉。
几个常用值要记熟。p p p 为素数时 φ ( p ) = p − 1 \varphi(p)=p-1 φ ( p ) = p − 1 ,简化剩余系就是 { 1 , 2 , … , p − 1 } \{1,2,\dots,p-1\} { 1 , 2 , … , p − 1 } 。p k p^k 时 ,去掉 的倍数即可。若 互素,则 。合数模要把公式乘开,不要看见 就抄上去。
公式可以从完全剩余系读出来。最小非负完全剩余系有 n n n 个数。对每个素因子 p ∣ n p\mid n p ∣ n ,其中 p p p 的倍数占 1 / p 1/p 1/ p ,留下比例 1 − 1 / p 1-1/p 1 − 1/ p 。不同素因子对应的「被 p p 整除」可以一起筛,乘积就是 。所以 不是外加的计数函数,它就是「从完全剩余系里抽出简化剩余系」的那次筛选。
欧拉定理是简化剩余系最直接的应用。设 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 ,r 1 , … , r φ ( n ) r_1,\dots,r_{\varphi(n)} r 1 , … , r φ ( n ) 是一组简化剩余系。由倍乘定理, 也是简化剩余系,因此两边的乘积模 相同:
∏ i r i ≡ ∏ i ( a r i ) = a φ ( n ) ∏ i r i ( m o d n ) \prod_{i} r_i \equiv \prod_{i}(ar_i) = a^{\varphi(n)}\prod_{i} r_i \pmod n i ∏ r i ≡ i 每个 r i r_i r i 都和 n n n 互素,乘积也可逆,两边约掉后得到
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1\pmod n a φ ( n ) ≡ 1 ( mod n ) 这里用到的不是「怎么解同余方程」,而是:互素倍乘只是把简化剩余系重排。φ ( n ) \varphi(n) φ ( n ) 既是元素个数,也是这个乘法群的阶。
另一件小事:完全剩余系永远是 n n n 个,简化剩余系永远是 φ ( n ) \varphi(n) φ ( n ) 个。φ ( n ) = n − 1 \varphi(n)=n-1 φ ( n ) = n − 1 当且仅当 n n n 为素数;n n n 合数时两者差得很多。n = 8 时一边 个、一边 个,不能混着数。
手算例子 { 0 , 1 , 2 , 3 , 4 , 5 , 6 } \{0,1,2,3,4,5,6\} { 0 , 1 , 2 , 3 , 4 , 5 , 6 } 是完全剩余系。7 7 7 是素数,φ ( 7 ) = 6 \varphi(7)=6 φ ( 7 ) = 6 ,简化剩余系是 { 1 , 2 , 3 , 4 , 5 , 6 } 。
平移 10 10 10 :{ 10 , 11 , 12 , 13 , 14 , 15 , 16 } \{10,11,12,13,14,15,16\} { 10 , 11 , 12 , 13 , 14 , 15 , 16 } ,模 7 7 7 依次是 { 3 , 4 , 5 , 6 , 0 , 1 , 2 } \{3,4,5,6,0,1,2\} { 3 , 4 , ,仍覆盖全部。倍乘 : ,模 是 ,也是完全剩余系。简化剩余系乘 得到 ,正好是原来六个可逆类的重排。
完全剩余系取 { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 } \{0,1,2,3,4,5,6,7\} { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 } ,简化剩余系取 { 1 , 3 , 5 , 7 } \{1,3,5,7\} { 1 , 3 , 5 , 7 } 。
{ 0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 } ≡ { 0 , 3 , 6 , 1 , 4 , 7 , 2 , 5 } ( m o d 8 ) \{0,3,6,9,12,15,18,21\}\equiv\{0,3,6,1,4,7,2,5\}\pmod 8 { 0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 } ≡ { 0 , 3 , 6 , 1 , 4 , { 3 , 9 , 15 , 21 } ≡ { 3 , 1 , 7 , 5 } ( m o d 8 ) \{3,9,15,21\}\equiv\{3,1,7,5\}\pmod 8 { 3 , 9 , 15 , 21 } ≡ { 3 , 1 , 7 , 5 } ( mod 8 ) 仍是 { 1 , 3 , 5 , 7 } \{1,3,5,7\} { 1 , 3 , 5 , 7 } 。
{ 0 , 2 , 4 , 6 , 8 , 10 , 12 , 14 } ≡ { 0 , 2 , 4 , 6 , 0 , 2 , 4 , 6 } ( m o d 8 ) \{0,2,4,6,8,10,12,14\}\equiv\{0,2,4,6,0,2,4,6\}\pmod 8 { 0 , 2 , 4 , 6 , 8 , 10 , 12 , 14 } ≡ { 0 , 2 , 4 , 6 , 0 , 只剩偶数类,重复出现,不是完全剩余系。简化剩余系乘 2 2 2 得到 { 2 , 6 , 2 , 6 } \{2,6,2,6\} { 2 , 6 , 2 , 6 } ,既有重复,又全不与 8 8 8 互素。
n = 15 n=15 n = 15 ,φ ( 15 ) = φ ( 3 ) φ ( 5 ) = 2 ⋅ 4 = 8 \varphi(15)=\varphi(3)\varphi(5)=2\cdot 4=8 φ ( 15 ) = φ ( 3 ) φ ( 5 ) = 2 ⋅ 4 = 8 。标准简化剩余系是
{ 1 , 2 , 4 , 7 , 8 , 11 , 13 , 14 } \{1,2,4,7,8,11,13,14\} { 1 , 2 , 4 , 7 , 8 , 11 , 13 , 14 } 一共八个,和公式一致。{ 0 , 1 , … , 14 } \{0,1,\dots,14\} { 0 , 1 , … , 14 } 是完全剩余系,十五个数。把其中与 15 15 15 不互素的 0 , 3 , 5 , 6 , 9 , 10 , 12 0,3,5,6,9,10,12 0 , 3 , 5 , 6 , 9 , 10 , 12 去掉,剩下的正好是上面那八个。
乘 4 4 4 (gcd ( 4 , 15 ) = 1 \gcd(4,15)=1 g cd( 4 , 15 ) = 1 )后,这八个数变成
{ 4 , 8 , 16 , 28 , 32 , 44 , 52 , 56 } ≡ { 4 , 8 , 1 , 13 , 2 , 14 , 7 , 11 } ( m o d 15 ) \{4,8,16,28,32,44,52,56\}\equiv\{4,8,1,13,2,14,7,11\}\pmod{15} { 4 , 8 , 16 , 28 , 32 , 44 , 52 , 56 } ≡ { 4 , 8 , 1 , 13 , 2 , 仍是同一集合。乘 5 5 5 则全部变成 0 0 0 或 5 5 5 或 10 10 10 ,立刻塌缩。
例四:对称完全剩余系 模 9 9 9 的对称完全剩余系是 { − 4 , − 3 , − 2 , − 1 , 0 , 1 , 2 , 3 , 4 } \{-4,-3,-2,-1,0,1,2,3,4\} { − 4 , − 3 , − 2 , − 1 , 0 , 1 , 2 , 3 , 4 } 。平移 4 4 4 得到 { 0 , 1 , 2 , 3 , 4 ,正是最小非负那一组,定理说这必然发生。其中与 互素的是 ,模 即 ,和标准简化剩余系 相同,个数 。
若把对称的九个数整体加 1 1 1 ,得到 { − 3 , − 2 , − 1 , 0 , 1 , 2 , 3 , 4 , 5 } \{-3,-2,-1,0,1,2,3,4,5\} { − 3 , − 2 , − 1 , 0 , 1 , 2 , 3 , 4 , 5 } ,仍是完全剩余系;其中与 9 9 9 互素的是 { − 2 , − 1 , 1 , 2 , 4 。和上一组 相比,丢掉了 (平移后变成 ,能被 整除),新进来 。个数碰巧还是 ,集合已经换了。这说明:平移后的完全剩余系可以立刻用,简化剩余系必须重新筛一遍,不能继承旧名单。
用 Python 构造 完全剩余系几乎不用构造:range(n) 就是最小非负那一组。简化剩余系按定义筛一遍即可;若只要个数,用欧拉函数的乘积公式更快。
from math import gcd
def complete_residues ( n : int ) -> list [ int ]:
""" 模 n 的最小非负完全剩余系。 """
if n <= 0 :
raise ValueError ( " 模数必须为正 " )
return list ( range ( n ))
def euler_phi ( n : int ) -> int :
""" φ(n)。 """
if n <= 0 :
raise ValueError ( " n 必须为正 " )
result , x
reduced_residues 对 n > 1 n>1 n > 1 会自动跳过 0 0 0 ,因为 gcd ( 0 , n ) = n ≠ 1 \gcd(0,n)=n\neq 1 g cd( 0 , n ) = n = 1 。is_complete 和 is_reduced 都先取模再比集合大小,避免「看起来有 n n 个数、模完却撞车」这种假阳性。
筛简化剩余系是 O ( n log n ) O(n\log n) O ( n log n ) (每个数一次 gcd \gcd g cd )。只要个数时用 euler_phi,复杂度是试除到 n \sqrt{n} n 。需要很多组随机代表时,可以先取出标准简化剩余系,再对每个元素加同一个 ,得到的仍是简化剩余系——这是「同一类换一个代表」,不是前面那个对整个集合做平移。
容易踩的坑 完全剩余系看个数是不是 n n n ,简化剩余系看个数是不是 φ ( n ) \varphi(n) φ ( n ) 。把 { 1 , 2 , … , n − 1 } \{1,2,\dots,n-1\} { 1 , 2 , … , n − 1 } 当成任意 n n n 的简化剩余系,只在 n n n 为素数时成立。 时 必须拿掉。
倍乘定理的前提是 gcd ( c , n ) = 1 \gcd(c,n)=1 g cd( c , n ) = 1 ,不是「c c c 不等于 0 0 0 」。模 12 12 12 乘 5 5 5 可以,乘 2 2 2 、乘 、乘 都会塌缩。写代码时若只判断 ,后面的置换论证全是错的。
平移保完全剩余系,不保简化剩余系。想换简化剩余系里某个数的代表,应当对单个 元素加 n n n 的倍数,而不是对整组加同一个与 n n n 无关的常数。
取模之后才谈「是不是同一组」。{ 1 , 3 , 5 , 7 } \{1,3,5,7\} { 1 , 3 , 5 , 7 } 和 { 9 , 11 , 13 , 15 } \{9,11,13,15\} { 9 , 11 , 13 , 15 } 模 8 8 8 是同一套简化剩余系,后者只是代表换了。比较两个剩余系,应比较 { a m o d n } \{a\bmod n\} { a 做成的集合,不要直接比列表。
φ ( n ) \varphi(n) φ ( n ) 的实现不要写成「从 1 1 1 数到 n n n 数互素的有几个」还以为自己在算公式。枚举是对的,但和乘积公式是两条路;对大 n n n 只问个数时,试除素因子更合适。还要注意 φ ( 1 ) = 1 \varphi(1)=1 φ ( 1 ) = 1 ,标准简化剩余系是 { 0 } \{0\} { 0 } 或 (两者同余),不要对 特判成空集。
列表里有重复,取模前看不出来。{ 1 , 9 , 17 } \{1,9,17\} { 1 , 9 , 17 } 三个数互不相同,模 8 8 8 却都是 1 1 1 ,既不是完全剩余系的一部分,更不是简化剩余系。写入集合前先 % n。
最后,剩余系是代表元的集合,不是某个方程的解集。它回答的是「模 n n n 有哪些类、哪些类可逆」,以及这些类在平移、互素倍乘下如何走动。把「选代表」和「求解」分开,后面做欧拉定理、原根和乘法阶时才不会把个数数错。
2
n − 1
}
0
,
1
,
…
,
n
−
1 }
k
{ 1 , 2 , 4 , 5 , 7 , 8 } \{1,2,4,5,7,8\} { 1 , 2 , 4 , 5 , 7 , 8 } gcd ( 0 , n ) = n ≠ 1 \gcd(0,n)=n\neq 1 g cd( 0 , n ) = n = 1 n
n
+
b
i = j
i
+
b ≡
( i −
1 +
b ) mod
n
0 , 1 , … , n − 1 0,1,\dots,n-1 0 , 1 , … , n − 1 =
1
n n n
c ( a i − a j ) c(a_i-a_j) c ( a i − a j ) gcd ( c , n ) = 1 \gcd(c,n)=1 g cd( c , n ) = 1 a i ≡ a j ( m o d n ) a_i\equiv a_j\pmod n a i ≡ a j ( mod n )
i
g cd
(
c
,
n
)
=
1
n ∣ ( a i − a j ) n\mid(a_i-a_j) n ∣ ( a i − a j ) g cd
(
c
,
n
)
=
1
g cd( c r i , n ) = 1
c r i ≡ c r j ( m o d n ) cr_i\equiv cr_j\pmod n c r i ≡ c r j ( mod n ) gcd ( c , n ) = 1 \gcd(c,n)=1 g cd( c , n ) = 1 r i ≡ r j ( m o d n ) r_i\equiv r_j\pmod n r i ≡ r j ( mod n )
mod
n }
p k
φ ( p k ) = p k − p k − 1 \varphi(p^k)=p^k-p^{k-1} φ ( p k ) = p k − p k − 1 φ ( m n ) = φ ( m ) φ ( n ) \varphi(mn)=\varphi(m)\varphi(n) φ ( mn ) = φ ( m ) φ ( n ) p
a r 1 , … , a r φ ( n ) ar_1,\dots,ar_{\varphi(n)} a r 1 , … , a r φ ( n )
∏
(
a
r i
)
=
a φ ( n ) i ∏ r i
( mod n )
n=8 n = 8
\{1,2,3,4,5,6\} { 1 , 2 , 3 , 4 , 5 , 6 }
5
,
6
,
0
,
1
,
2
}
{ 0 , 3 , 6 , 9 , 12 , 15 , 18 } \{0,3,6,9,12,15,18\} { 0 , 3 , 6 , 9 , 12 , 15 , 18 } { 0 , 3 , 6 , 2 , 5 , 1 , 4 } \{0,3,6,2,5,1,4\} { 0 , 3 , 6 , 2 , 5 , 1 , 4 } { 3 , 6 , 2 , 5 , 1 , 4 } \{3,6,2,5,1,4\} { 3 , 6 , 2 , 5 , 1 , 4 } 7
,
2
,
5
}
( mod 8 )
2
,
4
,
6
}
( mod 8 )
14
,
7
,
11
}
( mod 15 )
, 5 , 6 , 7 , 8 } \{0,1,2,3,4,5,6,7,8\} { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 }
{ − 4 , − 2 , − 1 , 1 , 2 , 4 } \{-4,-2,-1,1,2,4\} { − 4 , − 2 , − 1 , 1 , 2 , 4 } { 5 , 7 , 8 , 1 , 2 , 4 } \{5,7,8,1,2,4\} { 5 , 7 , 8 , 1 , 2 , 4 } { 1 , 2 , 4 , 5 , 7 , 8 } \{1,2,4,5,7,8\} { 1 , 2 , 4 , 5 , 7 , 8 } , 5 } \{-2,-1,1,2,4,5\} { − 2 , − 1 , 1 , 2 , 4 , 5 }
{ − 4 , − 2 , − 1 , 1 , 2 , 4 } \{-4,-2,-1,1,2,4\} { − 4 , − 2 , − 1 , 1 , 2 , 4 } =
n
,
n
p = 2
while p * p <= x :
if x % p == 0 :
while x % p == 0 :
x //= p
result = result // p * ( p - 1 )
p += 1 if p == 2 else 2
if x > 1 :
result = result // x * ( x - 1 )
return result
def reduced_residues ( n : int ) -> list [ int ]:
""" 模 n 的标准简化剩余系:1 到 n 中与 n 互素者。 """
if n <= 0 :
raise ValueError ( " 模数必须为正 " )
return [ a for a in range ( n ) if gcd ( a , n ) == 1 ]
def is_complete ( seq : list [ int ], n : int ) -> bool :
if len ( seq ) != n :
return False
return len ({ a % n for a in seq }) == n
def is_reduced ( seq : list [ int ], n : int ) -> bool :
if any ( gcd ( a , n ) != 1 for a in seq ):
return False
residues = { a % n for a in seq }
return len ( seq ) == len ( residues ) == euler_phi ( n )
def translate ( seq : list [ int ], b : int , n : int ) -> list [ int ]:
return [( a + b ) % n for a in seq ]
def scale ( seq : list [ int ], c : int , n : int ) -> list [ int ]:
return [( c * a ) % n for a in seq ]
if __name__ == " __main__ " :
n = 8
crs = complete_residues ( n )
rrs = reduced_residues ( n )
print ( crs ) # [0, 1, 2, 3, 4, 5, 6, 7]
print ( rrs , euler_phi ( n )) # [1, 3, 5, 7] 4
print ( is_complete ( translate ( crs , 5 , n ), n )) # True
print ( is_complete ( scale ( crs , 3 , n ), n )) # True
print ( is_complete ( scale ( crs , 2 , n ), n )) # False
print ( is_reduced ( scale ( rrs , 3 , n ), n )) # True
print ( is_reduced ( translate ( rrs , 1 , n ), n )) # False
n
k n kn k n
n = 9
3 3 3
mod
n }
完全剩余系与简化剩余系 · 无极之地