擴展歐幾里得求數字逆元
歐幾里得算法大家應該都聽說過,是一個求最大公約數的算法,又叫輾轉相除法。大致算法的思路就是,要求a,b兩個數的最大公約數,用其中一個數對另一個數取餘數,不妨記爲b%a,然後讓下一輪,b變爲a,a再變爲上一輪b%a的餘數繼續重複這樣的操作。
這裏簡單給出一個證明。設最大公約數爲t,則,則,所以這是一個縮小的序列,最終k縮小到0,就得到了最大公約數。
那麼什麼是擴展歐幾里得算法呢,這裏得先介紹一個定理,叫裴蜀定理,對於a,b肯定存在,能夠在求公約數的時候把x,y也求出來呢,這就是擴展歐幾里得算法的用處。算法在求公約數的時候加上了兩組數列,這數列在每一步的時候,計算一個等式,使得每一步都有,具體細節就不展開了。顯然這個公式中,最後一步,求出a,b的最大公約數時,也就求出了裴蜀定理中的x和y。
求出這個有什麼用呢,這個公式就是用來計算乘法逆元的。先解釋一下逆元的概念,假如有一個質數p,有一個正數a,存在a對p的逆元,則就是a對p的逆元。可以證明對於a小於質數p,逆元總是存在且唯一的。
把逆元的公式寫成裴蜀定理的形式,,因爲p是質數,所以對於兩個數的公約數就是1,然後對應上去歐幾里得算法,我們要求的就是裴蜀定理中的s。但是直接求出來s可能是負數,我們需要讓s對p求一次補,把它轉成正數。
但是我們到這裏只關心這個s,這個s也是一個序列,滿足上面的等式,可以看到s的迭代公式也是和b%a的餘數迭代公式類似的,具體證明可以大家自己查閱資料。下面直接給出代碼。緩衝一下,先看看gcd的代碼,然後大家自己做個對比。顯然兩個算法都是求出公約數的時候停止。
python求公約數的代碼
def gcd(a, b):
while a:
a,b= b%a ,a
return b
python擴展歐幾里得求逆元代碼
def ext_euclid(a, b): # b表示需要輸取模的質數
old_s,s=1,0
old_r,r=a,b
if b == 0:
return
else:
while(r!=0):
q=old_r//r
old_r,r=r,old_r-q*r
old_s,s=s,old_s-q*s
return old_s%b
C++擴展歐幾里得求逆元代碼
int ext_euclid(long a, long b)
{
if (b == 0)return 0;
long old_r = a, r = b;
long old_s = 1, s = 0;
while (old_r % r)
{
long q = old_r / r, tmp = old_r;
old_r = r;
r = tmp % r;
tmp = old_s;
old_s = s;
s = tmp - s * q;
cout << r << ',' << s << endl;
}
return s>0? s:b+s;
}
s和t的遞推式其實很好證明,只需要根據r的遞推式做一個等式代換即可,然後就可以把s和t都求出來,但是我們這裏只需要求出s即可。