欧几里德算法是用来求两个正整数最大公约数的算法。古希腊数学家欧几里德在其著作《The Elements》中最早描述了这种算法,所以被命名为欧几里德算法。
假如需要求 1997 和 615 两个正整数的最大公约数,用欧几里德算法,是这样进行的:
1997 ÷ \div ÷ 615 = 3 (余 152)
615 ÷ \div ÷ 152 = 4(余7)
152 ÷ \div ÷ 7 = 21(余5)
7 ÷ \div ÷ 5 = 1 (余2)
5 ÷ \div ÷ 2 = 2 (余1)
2 ÷ \div ÷ 1 = 2 (余0)
至此,最大公约数为1
以除数和余数反复做除法运算,当余数为 0 时,取当前算式除数为最大公约数,所以就得出了 1997 和 615 的最大公约数 1。
定理:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。最大公约数(Greatest Common Divisor)缩写为GCD。
g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b) = gcd(b,a\; mod\; b) gcd(a,b)=gcd(b,amodb) (不妨设 a > b a>b a>b 且 r = a m o d b r=a\; mod\; b r=amodb , r r r不为0)
证法一
证法二
假设 c = g c d ( a , b ) c = gcd(a,b) c=gcd(a,b),则存在 m , n m,n m,n,使 a = m c , b = n c a = mc, b = nc a=mc,b=nc
令 r = a m o d b r = a\; mod\; b r=amodb,即存在 k k k,使 r = a − k b = m c − k n c = ( m − k n ) c r = a-kb = mc - knc = (m-kn)c r=a−kb=mc−knc=(m−kn)c
故 g c d ( b , a m o d b ) = g c d ( b , r ) = g c d ( n c , ( m − k n ) c ) = g c d ( n , m − k n ) ∗ c gcd(b,a\; mod\; b) = gcd(b,r) = gcd(nc,(m-kn)c) = gcd(n,m-kn)*c gcd(b,amodb)=gcd(b,r)=gcd(nc,(m−kn)c)=gcd(n,m−kn)∗c
假设 d = g c d ( n , m − k n ) d = gcd(n,m-kn) d=gcd(n,m−kn), 则存在 x , y x,y x,y, 使 n = x d , m − k n = y d n = xd, m-kn = yd n=xd,m−kn=yd; 故 m = y d + k n = y d + k x d = ( y + k x ) d m = yd+kn = yd+kxd =(y+kx)d m=yd+kn=yd+kxd=(y+kx)d
故有 a = m c = ( y + k x ) d c , b = n c = x d c a = mc = (y+kx)dc, b = nc = xdc a=mc=(y+kx)dc,b=nc=xdc 可得 g c d ( a , b ) = g c d ( ( y + k x ) d c , x d c ) = d c gcd(a,b) = gcd((y+kx)dc,xdc) =dc gcd(a,b)=gcd((y+kx)dc,xdc)=dc
由于 g c d ( a , b ) = c gcd(a,b) = c gcd(a,b)=c, 故 d = 1 d = 1 d=1;即 g c d ( n , m − k n ) = 1 gcd(n,m-kn) = 1 gcd(n,m−kn)=1 故可得 g c d ( b , a m o d b ) = c gcd(b,a\; mod\; b) = c gcd(b,amodb)=c 故得证 g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b) = gcd(b,a\; mod\; b) gcd(a,b)=gcd(b,amodb)
注意:两种方法是有区别的。
def gcd(n1,n2):
if n1<n2:
n1,n2=n2,n1
while True:
m = np.mod(n1,n2)
if m == 0:
return n2
else:
n1,n2 = n2,m
扩展欧几里得算法(英语:Extended Euclidean algorithm)是欧几里得算法(又叫辗转相除法)的扩展。已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足等式:
a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
如果a是负数,可以把问题转化成:
∣ a ∣ ( − x ) + b y = g c d ( ∣ a ∣ , b ) |a|(-x)+by=gcd(|a|,b) ∣a∣(−x)+by=gcd(∣a∣,b)
然后令 x ′ = ( − x ) x'=(-x) x′=(−x)。
通常谈到最大公约数时,我们都会提到一个非常基本的事实:给予二个整数a、b,必存在整数x、y使得 a x + b y = g c d ( a , b ) ax + by = gcd(a,b) ax+by=gcd(a,b)。
有两个数a,b,对它们进行辗转相除法,可得它们的最大公约数——这是众所周知的。然后,收集辗转相除法中产生的式子,倒回去,可以得到 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的整数解。
扩展欧几里得算法可以用来计算模反元素(也叫模逆元),而模反元素在RSA加密算法中有举足轻重的地位。
例1:求 47 x + 30 y = 1 47x+30y=1 47x+30y=1的整数解
解:先用碾转相除法求47、30的最大公约数
q表示商、r表示余数
47 ÷ \div ÷ 30 = 1 (余 17) → q 1 = 1 , r 1 = 17 \rightarrow q_1=1,r_1=17 →q1=1,r1=17
30 ÷ \div ÷ 17 = 1(余13) → q 2 = 1 , r 2 = 13 \rightarrow q_2=1,r_2=13 →q2=1,r2=13
17 ÷ \div ÷ 13 = 1(余4) → q 3 = 1 , r 3 = 4 \rightarrow q_3=1,r_3=4 →q3=1,r3=4
13 ÷ \div ÷ 4 = 3 (余1) → q 4 = 3 , r 4 = 1 \rightarrow q_4=3,r_4=1 →q4=3,r4=1
4 ÷ \div ÷ 1 = 4 (余0) → q 5 = 4 , r 5 = 0 \rightarrow q_5=4,r_5=0 →q5=4,r5=0
用矩阵法来表示:
[ a b ] = Π i = 0 N [ q i 1 1 0 ] [ r N − 1 0 ] \begin{bmatrix} a \\ b \end{bmatrix}=\Pi_{i=0}^N\begin{bmatrix} q_i & 1 \\ 1 & 0 \end{bmatrix}\begin{bmatrix} r_{N-1} \\ 0 \end{bmatrix} [ab]=Πi=0N[qi110][rN−10]
即:
[ 47 30 ] = Π i = 0 5 [ q i 1 1 0 ] [ r 5 − 1 0 ] \begin{bmatrix} 47 \\ 30 \end{bmatrix}=\Pi_{i=0}^5\begin{bmatrix} q_i & 1 \\ 1 & 0 \end{bmatrix}\begin{bmatrix} r_{5-1} \\ 0 \end{bmatrix} [4730]=Πi=05[qi110][r5−10]
= [ 1 1 1 0 ] [ 1 1 1 0 ] [ 1 1 1 0 ] [ 3 1 1 0 ] [ 4 1 1 0 ] [ 1 0 ] =\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 3 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 4 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} =[1110][1110][1110][3110][4110][10]
= [ 47 11 30 7 ] [ 1 0 ] =\begin{bmatrix} 47 & 11 \\ 30 & 7 \end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} =[4730117][10]
所以:
[ 1 0 ] = [ − 7 11 30 − 47 ] [ 47 30 ] \begin{bmatrix} 1 \\ 0 \end{bmatrix}=\begin{bmatrix} -7 & 11 \\ 30 & -47 \end{bmatrix} \begin{bmatrix} 47 \\ 30 \end{bmatrix} [10]=[−73011−47][4730]
所以x、y有两组解,分别是 x = − 7 , y = 11 ; x = 30 , y = − 47 x=-7,y=11;x=30,y=-47 x=−7,y=11;x=30,y=−47
def ext_euclid(a,b):
flag = False
if a<b:
flag = True
a,b=b,a
Q=np.eye(2)
while True:
r = np.mod(a,b)
q = int(a/b)
if r != 0:
Q=np.dot(Q,np.array([[q,1],[1,0]]))
a,b = b,r
else:
Q=np.dot(Q,np.array([[q,1],[1,0]]))
break
_Q=np.linalg.inv(Q)
print(_Q)
x,y = int(np.round(_Q[0,0])),int(np.round(_Q[0,1]))
if flag == True:
print('xxx')
x,y = y,x
return (x,y)
或者如下方法:
def ext_euclid(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_euclid(b, a % b)
# q = gcd(a, b) = gcd(b, a%b)
x, y = y, (x - (a // b) * y)
return x, y, q
欧几里得算法
扩展欧几里得算法