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


greatest common divisor(最大公約數)

1.歐幾里得算法

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

其計算原理依賴於下面的定理:
兩個整數的最大公約數等於其中較小的那個數和兩數相除余數的最大公約數。
最大公約數(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:

函數內遞歸

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

函數遞歸:

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) 

 

 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM