很早就學過歐幾里得算法,但是一直不知道它的原理。幾乎每本算法書都會提到它,但是貌似只有數學書上才會見到它的原理。。。
前段時間粗粗看了點數論(《什么是數學》),驚訝於這個原理的奇妙。現在把它通俗地寫下來,以免自己忘記。
歐幾里得算法是求兩個數的最大公約數(Greatest Common Divisor (GCD))的算法,我們首先假設有兩個數 a 和 b,其中 a 是不小於 b 的數,
記 a 被 b 除的余數為 r,那么 a 可以寫成這樣的形式:
其中 q 是整數(我們不需要去管 q 到底是多少,這和我們的目標無關)。
現在假設 a 和 b 的一個約數為 u,那么 a 和 b 都能被 u 整除,即
s 和 t 都是整數(同樣的,我們只需要知道存在這樣的整數 s 和 t 就行)。
這樣可以得出
所以 r 也能被 u 整除,一般規律如下
a 和 b 的約數也整除它們的余數 r,所以 a 和 b 的任一約數同時也是 b 和 r 的約數。 —— 條件一
反過來可以得出
b 和 r 的任一約數同時也是 a 和 b 的約數。 ——條件二
這是因為對 b 和 r 每一個約數 v,有
於是有
由條件一和條件二可知
a 和 b 的約數的集合,全等於 b 和 r 的約數的集合。
於是
a 和 b 的最大公約數,就是 b 和 r 的最大公約數。
接下來用遞推法,
a ÷ b 余 r,現在設
b ÷ r 余 r1
r ÷ r1 余 r2
……
r(n-3) ÷ r(n-2) 余 r(n-1)
r(n-2) ÷ r(n-1) 余 r(n)=0
因為 a>=b,可以看出余數 r(n) 會越來越小,最終變成 0.
當 r(n-1)≠0 且 r(n) = 0 時,可知 r(n-2) 可被 r(n-1) 整除(余數為0嘛)
此時 r(n-2) 和 r(n-1) 的約數就只有:r(n-1) 和 r(n-1) 的因數,所以他們的最大公約數就是 r(n-1)!
所以 r(n-1) 就是 a 和 b 的最大公約數。(若 r = 0,則 b 為最大公約數)
這個遞推法寫成c語言函數是這樣的(比推導更簡潔...):
unsigned int Gcd(unsigned int M,unsigned int N){ unsigned int Rem; while(N){ Rem = M % N; M = N; N = Rem; } return Rem; }
可以發現這里沒有要求 M>=N,這是因為如果那樣,循環會自動交換它們的值。