扩展欧几里得求数字逆元


  欧几里得算法大家应该都听说过,是一个求最大公约数的算法,又叫辗转相除法。大致算法的思路就是,要求a,b两个数的最大公约数,用其中一个数对另一个数取余数,不妨记为b%a,然后让下一轮,b变为a,a再变为上一轮b%a的余数继续重复这样的操作。
  这里简单给出一个证明。设最大公约数为t,则 a = s t , b = l t a=st, b=lt ,则 b % a = k t ,   k l k < s b\%a=kt,\ k≤l且k<s ,所以这是一个缩小的序列,最终k缩小到0,就得到了最大公约数。
  那么什么是扩展欧几里得算法呢,这里得先介绍一个定理,叫裴蜀定理,对于a,b肯定存在 a s + b t = g c d ( a , b ) as+bt=gcd(a,b) ,能够在求公约数的时候把x,y也求出来呢,这就是扩展欧几里得算法的用处。算法在求公约数的时候加上了两组数列,这数列在每一步的时候,计算一个等式,使得每一步都有 b % a = a s + b t b\%a=as+bt ,具体细节就不展开了。显然这个公式中,最后一步,求出a,b的最大公约数时,也就求出了裴蜀定理中的x和y。
  求出这个有什么用呢,这个公式就是用来计算乘法逆元的。先解释一下逆元的概念,假如有一个质数p,有一个正数a,存在a对p的逆元 a 1 a 1 a % p = 1 a^{-1},满足a^{-1}*a\%p=1 ,则 a 1 a^{-1} 就是a对p的逆元。可以证明对于a小于质数p,逆元总是存在且唯一的。
  把逆元的公式写成裴蜀定理的形式, a a 1 + t p = 1 = g c d ( a , p ) a*a{-1}+tp=1=gcd(a,p) ,因为p是质数,所以对于 a < p a<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即可。

发布了42 篇原创文章 · 获赞 27 · 访问量 64万+

猜你喜欢

转载自blog.csdn.net/m0_38065572/article/details/105158498