1. 程式人生 > 其它 >輾轉相除法(歐幾里得)原理

輾轉相除法(歐幾里得)原理

技術標籤:C/C++常識性知識演算法導論c++

很早就學過歐幾里得演算法,但是一直不知道它的原理。幾乎每本演算法書都會提到它,但是貌似只有數學書上才會見到它的原理。。。

前段時間粗粗看了點數論(《什麼是數學》),驚訝於這個原理的奇妙。現在把它通俗地寫下來,以免自己忘記。

歐幾里得演算法是求兩個數的最大公約數(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,這是因為如果那樣,迴圈會自動交換它們的值。