欧几里得算法和扩展欧几里得算法

  欧几里得算法即辗转相除法,是求两个数的最大公因数的有效算法。而扩展欧几里得算法则可以求出等式sa+tb=gcd(a,b)中的s和t,该算法可以被用于求解模p运算的逆元,也是一个很有效的算法。

约定和解释

  1. 文章中所说的数除非特殊说明为非负整数
  2. ( a , b ) (a,b) (a,b)表示 a a a b b b的最大公因数

欧几里得算法(辗转相除法)

算法描述

有两个整数 a a a b b b, 并且 a > b a > b a>b, 则 a a a b b b有如下关系(欧几里得除法)( a a a为被除数, b b b为除数,求出余数 r r r):
a = q b + r ( 0 ≤ r < b ) a=qb+r \quad (0 \leq r < b) a=qb+r(0r<b)
我们令 a 2 = b ,   b 2 = r a_2=b, \ b_2=r a2=b, b2=r则类似的有(把除数 b b b和余数 r r r作为被除数和除数再次执行上述运算)
a 2 = q 2 b 2 + r 2 ( 0 ≤ r 2 < b 2 < b ) a_2=q_2 b_2 + r_2 \quad (0 \leq r_2 < b_2 < b) a2=q2b2+r2(0r2<b2<b)
依次类推, 必然存在 a n ,   b n ,   r n a_n, \ b_n, \ r_n an, bn, rn满足
a n = q n b n + r n ( r n = 0 ) a_n = q_n b_n + r_n \quad (r_n = 0) an=qnbn+rn(rn=0)

a n = q n b n a_n = q_n b_n an=qnbn
理由是 r > r 1 > r 2 . . . > r n r > r_1 > r_2...>r_n r>r1>r2...>rn r i ( i = 1 , 2 , 3... , n ) r_i (i = 1,2,3...,n) ri(i=1,2,3...,n)为大于等于0的整数, r i r_i ri依次减小最终必然会到0

此时的 b n b_n bn就是 a a a b b b的最大公因数

算法的正确性

欧几里得算法之所以有效,基于这样一个事实
若 a = q b + r ( 0 ≤ r < b ) , 则 a 和 b 的 最 大 公 因 数 与 b 和 r 的 最 大 公 因 素 相 同 若a=qb+r \quad (0 \leq r < b),则a和b的最大公因数与b和r的最大公因素相同 a=qb+r(0r<b)abbr
证明如下:
设 d = ( a ,   b ) , d 1 = ( b ,   r ) 则 有 d   ∣   ( a − q b ) , d 1   ∣   ( q b + r ) 即 d   ∣   r , 即 d 1   ∣   a 所 以 有 d   ∣   d ‘ 且 d 1   ∣   d 所 以 d = d 1 设d = (a, \ b),\quad d_1=(b, \ r) \\ 则有d \ | \ (a-qb), \quad d_1 \ | \ (qb + r) \\ 即d \ | \ r , 即 d_1 \ | \ a \\ 所以有 d \ | \ d^` 且 d_1 \ | \ d \\ 所以 d = d_1 d=(a, b),d1=(b, r)d  (aqb)d1  (qb+r)d  r,d1  ad  dd1  dd=d1
我们利用这个性质,把求较大的两个数 a a a b b b的公因数的问题不断转换成求两个较小的数(除数和余数)最大公因数的问题,直到这两个较小的数中有一个为0了,由于0和任何一个数x$ 的 最 大 公 因 数 就 是 的最大公因数就是 x$,因为就求出了最大公因数。

python实现

def gcd(big_num, small_num):
    remainder = big_num % small_num
    if remainder == 0:
        return small_num
    return gcd(small_num, remainder)

扩展欧几里得算法

算法描述

根据定理,对于任意整数 a a a b b b,必然存在整数 s s s t t t使得如下等式成立
s a + t b = ( a , b ) sa+tb=(a,b) sa+tb=(a,b)
要求出其中的 s s s t t t可以利用欧几里得算法求最大公因数的过程

在这里,为了更好的说明算法,我们使用 a 1 和 a 2 a_1和a_2 a1a2 ( a 1 > a 2 ) (a_1 > a_2) (a1>a2)来表示欧几里得算法中的 a 和 b a和b ab,按照欧几里得算法,有如下求 a 1 和 a 2 a_1和a_2 a1a2最大公因数 ( a 1 , a 2 ) (a_1,a_2) (a1,a2)的过程
a 1 = q 1 a 2 + a 3 a 2 = q 2 a 3 + a 4 a 3 = q 3 a 4 + a 5 . . . a n − 3 = q n − 3 a n − 2 + a n − 1 a n − 2 = q n − 2 a n − 1 + a n a n − 1 = q n − 1 a n a_1=q_1a_2+a_3 \\ a_2=q_2a_3+a_4 \\ a_3=q_3a_4+a_5 \\ ... \\ a_{n-3}=q_{n-3}a_{n-2}+a_{n-1} \\ a_{n-2}=q_{n-2}a_{n-1}+a_n \\ a_{n-1} = q_{n-1}a_n a1=q1a2+a3a2=q2a3+a4a3=q3a4+a5...an3=qn3an2+an1an2=qn2an1+anan1=qn1an
a n a_n an就是 a 1 和 a 2 a_1和a_2 a1a2的最大公因数

首先根据欧几里得算法的求解过程,我们容易得到
( a 1 , a 2 ) = a n = a n − 2 − q n − 2 a n − 1 (a_1,a_2) = a_n = a_{n-2} - q_{n-2}a_{n-1} (a1,a2)=an=an2qn2an1
根据上式子,可以得到对于 a n − 2 和 a n − 1 a_{n-2}和a_{n-1} an2an1来说使等式
( a 1 , a 2 ) = s n − 2   ⋅   a n − 2 + t n − 2   ⋅   a n − 1 式 1 (a_1, a_2) = s_{n-2} \ \cdot \ a_{n-2} + t_{n-2} \ \cdot \ a_{n-1} \qquad 式1 (a1,a2)=sn2  an2+tn2  an11
成立的 s n − 2 和 t n − 2 s_{n-2}和t_{n-2} sn2tn2的值,即
s n − 2 = 1 t n − 2 = − q n − 2 s_{n-2} = 1 \\t_{n-2} = -q_{n-2} sn2=1tn2=qn2
现在我们想要计算对于 a n − 3 和 a n − 2 a_{n-3}和a_{n-2} an3an2来说等式
( a 1 , a 2 ) = s n − 3   ⋅   a n − 3 + t n − 3   ⋅   a n − 2 式 2 (a_1, a_2) = s_{n-3} \ \cdot \ a_{n-3} + t_{n-3} \ \cdot \ a_{n-2} \qquad 式2 (a1,a2)=sn3  an3+tn3  an22
成立的 s n − 3 和 t n − 3 s_{n-3}和t_{n-3} sn3tn3的值

根据欧几里得算法的求解过程,有如下等式对n>3都成立
a n − 1 = a n − 3 − q n − 3 a n − 2 式 3 a_{n-1} = a_{n-3} - q_{n-3}a_{n-2} \qquad 式3 an1=an3qn3an23
将式3中 a n − 1 a_{n-1} an1的表达式带入式1得到
( a 1 , a 2 ) = t n − 2   ⋅   a n − 3 + ( s n − 2 − q n − 3 ⋅ t n − 2 )   ⋅   a n − 2 式 4 (a1, a2) = t_{n-2} \ \cdot \ a_{n-3} + (s_{n-2}-q_{n-3} \cdot t_{n-2}) \ \cdot \ a_{n-2} \qquad 式4 (a1,a2)=tn2  an3+(sn2qn3tn2)  an24
可以看到,我们在式2中需要求的 s n − 3 和 t n − 3 s_{n-3}和t_{n-3} sn3tn3求出来了,且这个关系也对n>3都成立
s n − 3 = t n − 2 t n − 3 = s n − 2 − q n − 3   ⋅   t n − 2 s_{n-3} = t_{n-2} \\ t_{n-3} = s_{n-2} - q_{n-3} \ \cdot \ t_{n-2} sn3=tn2tn3=sn2qn3  tn2
按照这个关系,我们可以一直向前推,直到 s 1 和 t 1 s_1和t_1 s1t1满足
( a 1 , a 2 ) = s 1   ⋅ a 1 + t 1   ⋅   a 2 (a_1,a_2)=s_1 \ \cdot a_1 + t_1 \ \cdot \ a_2 (a1,a2)=s1 a1+t1  a2
从而解出了想要求出的 s s s t t t

注: s s s t t t不唯一的(只考虑绝对值不同),例如:
6720 × 46480 + ( − 19713 ) × 39423 = 1 ( − 22703 ) × 46480 + 26767 × 39423 = 1 6720 \times 46480 + (-19713) \times 39423 = 1 \\ (-22703) \times 46480 + 26767 \times 39423 = 1 6720×46480+(19713)×39423=1(22703)×46480+26767×39423=1
这似乎说明39423模46480的逆元有两个,但实际上有 ( − 19713 ) + 46480 = 26767 (-19713) + 46480 = 26767 (19713)+46480=26767
− 19713 ≡ 26767   ( m o d   46480 ) -19713 \equiv 26767 \ (mod \ 46480) 1971326767 (mod 46480), 对于 a a a b b b不互质的情况,暂不清楚。

算法的应用

该算法可以在 a a a p p p互质时被用来快速求 a a a p p p逆元 a ‘ a^` a

因为若
s   ⋅   a + t   ⋅   p = 1 s \ \cdot \ a + t \ \cdot \ p = 1 \\ s  a+t  p=1
则有
s   ⋅   a ≡ 1   ( m o d   p ) s \ \cdot \ a \equiv 1 \ (mod \ p) s  a1 (mod p)
其中 s s s就是 a a a的逆元 a ‘ a^` a

python实现

# 参数为两个数,大数在前小数在后
# 返回值为s,t和两个数的最大公因数
def gcd_ext(big_num, small_num):
    remainder = big_num % small_num
    iq = int(big_num / small_num)
    if small_num % remainder == 0:
        s = remainder
        t = -iq
        return (s, t, remainder)
    s_last, t_last, gcd = gcd_ext(small_num, remainder)
    s = t_last
    t = s_last - t_last * iq
    return (s, t, gcd)

参考资料

信息安全数学基础(第2版)陈恭亮【清华大学出版社】

你可能感兴趣的:(数学)