預備知識(不嚴謹定義)
整除:簡單來說, \(a = nb\), 則有\(b|a\),讀作b整除a
約數(divisor):上面整除的例子里,b就是a的約數,公約數就是多個數的共有約數,如2就是4、6、8的公約數
最大公約數(greast common divisor, 簡稱gcd):顧名思義,公約數里最大的一個,設\(gcd(a,b)=m\),則任取a、b的公約數c,有\(c <= m\),需要注意的是,最大公約數往往是整數,特殊的:
- 若\(b|a\), 則\(gcd(a, b)=b\)
- 任取整數\(n\),有\(gcd(0, n)=n\)
互素(relatively prime):兩個數的最大公約數是1,那么我們就稱這兩個數的互素的
如果我們要求最大公約數,我們先來想一下最簡單的思路。
假設\(a>b\),我們使用暴力求解的方式,從1開始,設置一個變量存儲最大公約數值,每發現一個既能整除a又能整除b的數,將其置為最大公約數,直到遍歷到b為止。粗一看,時間復雜度也並不很高,似乎也是可行的方法。但實際上,在實際的密碼學程序中,需要大量的這類操作,並且操作的數往往是非常大的數,這時,這種方法就顯得十分低效,而歐幾里德方法就是為了能夠高效的求取最大公約數。
歐幾里德算法
首先我們來看,設
那么\(r = a-q*b\),由於\(d|a、d|b\),則有\(d|(a-q*b)=r\),即d也是b和r的最大公約數,此外,又有\(b>r => b=q_1*r+r_1\)以此類推,就得到了我們的歐幾里德算法。
算法描述為:
- 將輸入置為\(a>b\)
- 令\(a=q*b+r\)
- 若\(r=0\),則\(gcd(a,b)=b\)
- 否則,令\(a := b, b := r\), 注意這里的:=是賦值操作,重復2
建議自己模擬一下,易於理解!
歐幾里德算法的實現
# 加減法的實現對計算機的計算方式更友善
def gcd1(a, b):
a, b = max(a, b), min(a, b)
while a != b:
a, b = max(b, a-b), min(b, a-b)
return a
def gcd2(a, b):
a, b = max(a, b), min(a, b)
while a % b != 0:
a, b = b, a%b
return b
實用的歐幾里德算法
上面只是歐幾里德算法的直接實現,效率較低,不能滿足實際環境的需要。
通常的生產代碼中使用的最大公約數算法是一種稱作binary GCD的算法,其算法描述如下,
openssl中使用的BN_gcd便使用了該算法