扩展欧几里得求数字逆元
欧几里得算法大家应该都听说过,是一个求最大公约数的算法,又叫辗转相除法。大致算法的思路就是,要求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即可。