关注我的公众号c137Lab获取更多相关内容
Def: 两个数 a a a 和 b b b (不全为零)的最大公因数是整除他们两个的最大数,记为 g c d ( a , b ) gcd(a,b) gcd(a,b). 若 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,则称 a a a 和 b b b 互素.
欧几里得算法
- 下面先给出欧几里得算法的定理
定理(欧几里得算法) 要计算两个整数 a a a 与 b b b 的最大公因数,先令 r − 1 = a r_{-1}=a r−1=a且 r 0 = b r_0=b r0=b,然后计算相继的商和余数
r i − 1 = q i + 1 ∗ r i + r i − 1 ( i = 0 , 1 , 2 , ⋯ ) r_{i-1}=q_{i+1}*r_i+r_{i-1}\quad(i=0,1,2,\cdots) ri−1=qi+1∗ri+ri−1(i=0,1,2,⋯)
直到某余数 r i − 1 r_{i-1} ri−1 为 0. 最后的非零余数 r n r_n rn 就是 a a a 与 b b b 的最大公因数。
- 浅显易懂的举例:计算 g c d ( 36 , 132 ) gcd(36, 132) gcd(36,132)
- 将 132 除以 36 得商 3与余数 24
132 = 3 ∗ 36 + 24 132=3*36+24 132=3∗36+24 - 取 36 ,用前一步的余数 24 除 36 得
36 = 1 ∗ 24 + 12 36=1*24+12 36=1∗24+12 - 用 12 除 24 求得余数 0
24 = 2 ∗ 12 + 0 24=2*12+0 24=2∗12+0
欧几里得算法说明当得到余数 0 时,前一步的余数就是最初两个数的最大公因数。故求得 g c d ( 132 , 36 ) = 12 gcd(132, 36)=12 gcd(132,36)=12
- 下面我们分析欧几里得算法,假设求 g c d ( a , b ) gcd(a, b) gcd(a,b) ,对于一般情景,有:
a = q 1 ∗ b + r 1 (1) a=q_1*b+r_1 \tag{1} a=q1∗b+r1(1)
b = q 2 ∗ r 1 + r 2 (2) b=q_2*r_1+r_2 \tag{2} b=q2∗r1+r2(2)
r 1 = q 3 ∗ r 2 + r 3 (3) r_1=q_3*r_2+r_3 \tag{3} r1=q3∗r2+r3(3)
r 2 = q 4 ∗ r 3 + r 4 (4) r_2=q_4*r_3+r_4 \tag{4} r2=q4∗r3+r4(4)
⋮ \vdots ⋮
r n − 3 = q n − 1 ∗ r n − 2 + r n − 1 (5) r_{n-3}=q_{n-1}*r_{n-2}+r_{n-1} \tag{5} rn−3=qn−1∗rn−2+rn−1(5)
r n − 2 = q n ∗ r n − 1 + r n (6) r_{n-2}=q_n*r_{n-1}+r_n \tag{6} rn−2=qn∗rn−1+rn(6)
r n − 1 = q n + 1 ∗ r n + 0 (7) r_{n-1}=q_{n+1}*r_n+0 \tag{7} rn−1=qn+1∗rn+0(7)
如果令 r 0 = b r_0=b r0=b 且 r − 1 = a r_{-1}=a r−1=a 则每行可以写成:
r i − 1 = q i + 1 ∗ r i + r i + 1 r_{i-1}=q_{i+1}*r_i+r_{i+1} ri−1=qi+1∗ri+ri+1
那么,为什么说 r n r_n rn 就是 a a a 与 b b b 的最大公因数呢?我们先来证明 r n r_n rn 是 a a a 与 b b b 的公因数:
**证:**式 ( 7 ) (7) (7) 表明 r n r_n rn 整除 r n − 1 r_{n-1} rn−1 ,再观察式 ( 6 ) (6) (6) ,因为 r n r_n rn 整除 r n − 1 r_{n-1} rn−1 和 r n r_n rn,可以发现 r n r_n rn 整除 r n − 2 r_{n-2} rn−2 。
向上递推直到 i = 0 i=0 i=0 ,此时可以得到 r n r_n rn 整除 r − 1 r_{-1} r−1 和 r 0 r_0 r0 ,即 r n r_n rn 整除 a a a 和 b b b ,故 r n r_n rn 是 a a a 与 b b b 的公因数.
接下来证明 r n r_n rn 是 a a a 与 b b b 的最大公因数:
**证:**假设 d d d 是 a a a 和 b b b 的任意公因数。从式 ( 1 ) (1) (1) 可得, d d d 整除 a , b , r 1 a,b,r_1 a,b,r1 ,再观察式 ( 2 ) (2) (2) 可得 d d d 整除 b , r 1 , r 2 b,r_1,r_2 b,r1,r2 ,向下递推直到式 ( 7 ) (7) (7) ,可得 d d d 整除 r n r_n rn 。
由于 d d d 是 a a a 和 b b b 的任意公因数且 d d d 整除 r n r_n rn ,可得 r n r_n rn 为 a a a 和 b b b 的最大公因数
既然已经得到了欧几里得算法的确可以求得最大公因数。那么,这一算法的效率如何呢,要经过多少次计算才能得到为 0 的余数呢?
或者说,这一算法有没有可能因为无法得到为 0 的余数而永无止境?
以下证明过程,证明了欧几里得算法至多在 2 l o g 2 ( b ) 2log_2(b) 2log2(b) 步终止:
**证:**已知以下两式:
r i − 2 = q i ∗ r i − 1 + r i (8) r_{i-2}=q_i*r_{i-1}+r_i\tag{8} ri−2=qi∗ri−1+ri(8)r i − 1 = q i + 1 ∗ r i + r i + 1 i = 0 , 1 , 2 , ⋯ (9) r_{i-1}=q_{i+1}*r_i+r_{i+1}\quad i=0,1,2,\cdots\tag{9} ri−1=qi+1∗ri+ri+1i=0,1,2,⋯(9)
式 ( 8 ) (8) (8)减去式 ( 9 ) (9) (9)整理得
r i − 2 = ( q i + 1 ) ∗ r i − 1 + ( 1 − q i + 1 ) ∗ r i − r i + 1 (10) r_{i-2}=(q_i+1)*r_{i-1}+(1-q_{i+1})*r_i-r_{i+1}\tag{10} ri−2=(qi+1)∗ri−1+(1−qi+1)∗ri−ri+1(10)
将式 ( 9 ) (9) (9)代入式 ( 10 ) (10) (10)整理得:
( q i ∗ q i + 1 + 1 ) ∗ r i + q i ∗ r i + 1 = r i − 2 (q_i*q_{i+1}+1)*r_i+q_i*r_{i+1}=r_{i-2} (qi∗qi+1+1)∗ri+qi∗ri+1=ri−2
由于 q q q 是正整数,可得:
r i − 2 > 2 r i r_{i-2}>2r_i ri−2>2ri
通过递推可以得到:
2 − i 2 ∗ b > r i 2^{-\frac{i}{2}}*b>r_i 2−2i∗b>ri
当 2 − i 2 ∗ b = 1 2^{-\frac{i}{2}}*b=1 2−2i∗b=1 时算法结束,此时步数 i = 2 l o g 2 ( b ) i=2log_2(b) i=2log2(b)
What‘s more:
由于欧几里得算法的最大步数是 2 l o g 2 ( b ) 2log_2(b) 2log2(b),十进制数 b b b 可以表示为 b = m ∗ 1 0 n b=m*10^n b=m∗10n 将其代入,可以得出:欧几里得算法的最大步数约等于 b b b 的位数的 7 倍。因此,即使是在对非常大的数求公因式时,依然可以保持很高的效率。
欧几里得算法的代码实现
a = int(input())
b = int(input())
if a == 0 or b == 0:
print("illegal input")
else:
while b != 0:
a, b = b, a % b
print("gcd(a,b)=", a)
参考文献:A Brief Introduction to Number Theory --Joseph H.Silverman