Python 最大公約數的歐幾里得算法及Stein算法

greatest common divisor(最大公約數)算法

1.歐幾里得算法函數

歐幾里德算法又稱展轉相除法,用於計算兩個正整數a,b的最大公約數。spa

其計算原理依賴於下面的定理:
兩個整數的最大公約數等於其中較小的那個數和兩數相除餘數的最大公約數。
最大公約數(greatest common divisor)縮寫爲gcd。
gcd(a,b) = gcd(b,a mod b) (不妨設a>b 且r=a mod b ,r不爲0),以此展轉相除獲得最終結果。
 
證實:
a能夠表示成a = kb + r(a,b,k,r皆爲正整數,且r<b),則r = a mod b
假設d是a,b的一個公約數,記做d|a,d|b,即a和b均可以被d整除。
而r = a - kb,兩邊同時除以d,r/d=a/d-kb/d=m,等式左邊可知m爲整數,所以d|r
所以d也是b,a mod b的公約數
所以(a,b)和(b,a mod b)的公約數是同樣的,其最大公約數也必然相等,得證。
 
代碼實現:
C++:
int gcd(int a,int b){
    if (a < b)
        std::swap(a, b);
    return b == 0 ? a : gcd(b, a % b);        
}

 

Python:設計

函數內遞歸code

1 def gcd(a, b):
2     if a < b:
3         a, b = b, a
4     while b != 0:
5         a,b = b,a%b
6     return a

函數遞歸:blog

1 def gcd(a, b):
2     if b == 0:
3         return a
4     return gcd(b, a % b)

2.Stein算法:遞歸

歐幾里德算法是計算兩個數最大公約數的傳統算法,不管從理論仍是從實際效率上都是很好的。可是卻有一個致命的缺陷,這個缺陷在素數比較小的時候通常是感受不到的,只有在大素數時纔會顯現出來。
通常實際應用中的整數不多會超過64位(固然如今已經容許128位了),對於這樣的整數,計算兩個數之間的模是很簡單的。對於字長爲32位的平臺,計算兩個不超過32位的整數的模,只須要一個指令週期,而計算64位如下的整數模,也不過幾個週期而已。可是對於更大的素數,這樣的計算過程就不得不禁用戶來設計,爲了計算兩個超過64位的整數的模,用戶也許不得不採用相似於多位數除法手算過程當中的試商法,這個過程不但複雜,並且消耗了不少CPU時間。對於現代密碼算法,要求計算128位以上的素數的狀況比比皆是,設計這樣的程序迫切但願可以拋棄除法和取模。
 
證實:
由J. Stein 1961年提出的Stein算法很好的解決了歐幾里德算法中的這個缺陷,Stein算法只有整數的移位和加減法,爲了說明Stein算法的正確性,首先必須注意到如下結論:
gcd(a,a)=a,也就是一個數和其自身的公約數還是其自身。
gcd(ka,kb)=k gcd(a,b),也就是最大公約數運算和倍乘運算能夠交換。特殊地,當k=2時,說明兩個偶數的最大公約數必然能被2整除。
當k與b互爲質數,gcd(ka,b)=gcd(a,b),也就是約掉兩個數中只有其中一個含有的因子不影響最大公約數。特殊地,當k=2時,說明計算一個偶數和一個奇數的最大公約數時,能夠先將偶數除以2。
 
代碼實現:
Python:
 1 def gcd_Stein(a, b):  
 2     if a < b:
 3         a, b = b, a
 4     if (0 == b):
 5         return a
 6     if a % 2 == 0 and b % 2 == 0:
 7         return 2 * gcd_Stein(a/2, b/2)
 8     if a % 2 == 0:
 9         return gcd_Stein(a / 2, b)
10     if b % 2 == 0:
11         return gcd_Stein(a, b / 2)
12     
13     return gcd_Stein((a + b) / 2, (a - b) / 2) 
相關文章
相關標籤/搜索