乘法逆元的定义:
A * X MOD N == 1则称X为A关于模N的乘法逆元。
注:
只有两个数互素的时候才会有乘法逆元。
两个数不互素是没有乘法逆元的。
费马小定理:
利用费马小定理只能求出N为素数的情况下的乘法逆元,所以还是需要采用扩展欧几里德算法来计算普遍情况下的乘法逆元的情况。
下面的算法是求出n的简化剩余集的元素个数,利用
an-1==1 MOD n
//n是素数,且a不能被n整除,且a与n互素才可以
int fai = 1;
for (int i = 2; i < n; i++)
{
if (gcd(i, n) == 1)
fai++;
}
cout<<(int)pow(a, fai - 1) %n;
扩展欧几里德算法:
N*X + A*Y == 1。
采用逆推的方式,首先利用欧几里德算法,求最大共因子到1,
N A
26 17
17 9
9 8
8 1
当A为1的时候,就到了需要逆推的时候,
定义x为递归的时候a的系数,y为b的系数
1 = 9 – 8 系数为x=1和 y=-9/8==-1
= 9 - (17 – 9 * 17/9) 除法为向下取整,系数为 x=-1=上一个的y
y=1-17/9*(-1)=2其中1为上一个的x,-1为上一层y
= ……直到结束
最后的y即为乘法逆元。
考虑特殊情况:
1. 当a>n的时候,例如5 * X MOD 3 == 1
此时需要将N加上A,计算5 * X MOD 8== 1
计算出乘法逆元后,y加上x即可。
5 3 =>3 2=>2 1
8 5=>5 3=>3 2=>2 1
最后计算的结果为8与5的系数,而结果需要的是5与3的系数,但是8=5+3,所以分解之后的结果为y+=x。
2. 当系数结果为负数的时候
如17 * X MOD 26 == 1,
最后Y == -3。显然乘法逆元不能为负数,且范围应为(1, N-1]之间的整数,所以需要将YMOD N即可,后在计算机内计算模余方法的缺陷,如果最后仍为负数,需要讲Y加上N。
-3+26 = 23。
利用等式加减17*26仍不变的性质。
3. 两个数不互素
输出没有乘法逆元即可。
运行结果:
代码 :
#include "iostream"
using namespace std;
//记gcd(a,b)表示非负整数a,b的最大公因数,那么:gcd(a,b)=gcd(b,a%b)
int gcd(int a, int b)
{
if (a < b)
{
int temp = b;
b = a;
a = temp;
}
if (a%b == 0)
return b;
else
return gcd(b, a%b);
}
int ExtendEculid(int a, int b, int &x, int &y, int c)
{
if (b == 1)
{
x = 1;
y = -c/a;
return a;
}
int result = ExtendEculid(b, a%b, x, y, a);
if (c != 0)
{
int temp = x;
x = y;
y = temp - c / a*y;
}
return result;
}
//a*x+b*y=k,调用扩展欧几里德函数
int Generate(int a, int b)
{
int x, y;
if (b > a)
{
a += b;
int result = ExtendEculid(a, b, x, y, 0);
y += x;
a -= b;
}
else
{
int result = ExtendEculid(a, b, x, y, 0);
}
y %= a;
if (y < 0)
return y + a;
else
return y;
}
int main()
{
while (1)
{
cout << "a * x mod n == 1\n请输入a:";
int a, b;
cin >> a;
cout << "请输入n:";
cin >> b;
if (gcd(a, b) != 1)
cout << "两个数不互素,没有乘法逆元!" << endl << endl;
else
cout << "乘法逆元是" << Generate(b, a) << endl << endl;
}
}