求逆元
求整数上乘法逆元#
求 7 关于 26 的逆元!
扩展欧几里得算法#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h> #include <stdlib.h> //欧几里得函数 void exgcd( int a, int b, int &x, int &y, int &d) { if (!b) { d = a, x = 1, y = 0; } else { exgcd(b, a % b, y, x, d); y -= x * (a / b); } } int inv( int t, int p) { //返回t对p的逆元 int d, x, y; exgcd(t, p, x, y, d); return (x % p + p) % p; //x可能为负,也可能过大 } int main() { int m = 7, n = 26; printf ( "%d" , inv(m, n)); return 0 ; } |
或者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <stdio.h> #include <stdlib.h> int exgcd( int a, int b, int &x, int &y) //扩展欧几里得算法 { if (b==0) { x=1,y=0; return a; } int ret=exgcd(b,a%b,y,x); y-=a/b*x; return ret; } int getInv( int a, int mod) //求a在mod下的逆元,不存在逆元返回-1 { int x,y; int d=exgcd(a,mod,x,y); return d==1?(x%mod+mod)%mod:-1; } int main() { int m = 7, n = 26; printf ( "%d" , getInv(m, n)); return 0 ; } |
手算 #
方法1:辗转相除法#
求7关于26的逆元,即
:
设
26 / 7 = 3 余 5
7 / 5 = 1 余 2
5 / 2 = 2 余 1
则:
1 = 5 - 2 * 2
1 = 5 - 2 * (7 - 5 * 1) = 3 * 5 - 2 * 7
1 = 3 * (26 - 3 * 7) - 2 * 7= 3 * 26 - 11 * 7
故
方法2#
参考:链接
(1)原理
首先对余数进行辗转相除:
N = A * a0 + r0
A = r0 * a1 + r1
r0 = r1 * a2 + r2
r1 = r2 * a3 + r3
…
rn-2 = rn-1 * an + rn
rn-1 = rn * an+1 + 0
对上面的商数逆向排列(不含余数为0的商数):
其中:
b-1 = 1
b0 = an
bi = an-1 * bi-1 + bi-2
商个数为偶数,则bn即为所求的逆元B;
商个数为奇数,则N-bn即为所求的逆元B
(2)举例
求7关于26的逆元:
辗转相除法:
26 = 3 * 7 + 5
7 = 1 * 5 + 2
5 = 2 * 2 + 1
因为商的个数为奇数,故 7-1 = 26 - 11 = 15
方法3:Bezout恒等式#
(1)原理
用矩阵行初等变换的方法求Bezout,进而求逆元
参考:链接
方法4:扩展欧几里得算法#
参考:求逆元算法实现 求逆元
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #include<iostream> using namespace std; //递归求解 int exgcd( int a, int b, int & x, int & y) { if (b == 0) { x = 1; y = 0; return a; } int gcd = exgcd(b, a % b, x, y); int x2 = x, y2 = y; x = y2; y = x2 - (a / b) * y2; return gcd; } //非递归求解 int exgcd01( int a, int b, int & x, int & y) { int x1, y1, x0, y0; x0 = 1; y0 = 0; x1 = 0; y1 = 1; x = 0; y = 1; int r = a % b; int q = (a - r) / b; while (r) { x = x0 - q * x1; y = y0 - q * y1; x0 = x1; y0 = y1; x1 = x; y1 = y; a = b; b = r; r = a % b; q = (a - r) / b; } return b; } int main() { int x, y, a, b,option; cout << "扩展欧几里得算法" << endl; cout << endl << "请选择:1、递归求解;2、非递归求解" << endl; cin >> option; if (option == 1) { cout << "请输入a和b:" << endl; cin >> a >> b; cout << "a和b的最大公约数:" << endl; cout << exgcd(a, b, x, y) << endl; cout << "ax+by=gcd(a,b) 的一组解是:" << endl; cout << x << " " << y << endl; } else if (option == 2) { cout << "请输入a和b:" << endl; cin >> a >> b; cout << "a和b的最大公约数:" << endl; cout << exgcd01(a, b, x, y) << endl; cout << "ax+by=gcd(a,b) 的一组解是:" << endl; cout << x << " " << y << endl; } else cout << "请重新输入!" << endl; return 0; } |
费马小定理#
该方法速度非常快
(1)原理
(2)代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <stdio.h> #include <math.h> int main() { int m, n, x; puts ( "基于费马定理求逆元\n" ); puts ( "对m * x = 1 mod n,求x\n" ); printf ( "请输入m=" ); scanf ( "%d" , &m); printf ( "请输入n=" ); scanf ( "%d" , &n); x = ( int ) pow (m, n - 2) % n; printf ( "x=%d\n" , x); system ( "pause" ); return 0; } |
大数求逆元#
使用miracl库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | int main() { /*求m的逆元n,即m.n=1 mod p*/ printf ( "求m的逆元n,即m.n=1 mod p\n\n" ); miracl* mip = mirsys(MAX_D + 10, 10); big p = mirvar(0); big m = mirvar(0); big n = mirvar(0); big one = mirvar(0); char one_0[2] = { "1" }; cinstr(one, one_0); printf ( "请输入(m,p):\n" ); cinnum(m, stdin); cinnum(p, stdin); xgcd(m, p, n, n, one); printf ( "\n输出n:" ); cotnum(n, stdout); mirexit(); system ( "pause" ); return 0; } |
多项式的乘法逆元#
Bezout恒等式#
(1)原理:用矩阵行初等变换的方法求Bezout,进而求逆元
设a , b ∈ Z ,则a , b的最大公约数可以表示为:
g c d ( a , b ) = d = s a + t b
把d = s a + t b称作Bezout恒等式。
更多Bezout恒等式请参考:链接
(2)矩阵的行初等变换求解Bezout恒等式
这里以一个具体的实例来说明,求g c d ( 5 , 177 ):
1、先把欲求的两个数写成如下的矩阵形式,即是以5和17为第一列,后面拼一个单位矩阵。
2、将上述矩阵行初等变换至5和17这两个位置任意一个为0即可,另一个位置的值就是a和b的最大公约数。
3、得到Bezout恒等式,上述两个*位置表示这个问题中,不需要关注那两个位置的值
1 = 177 ∗ − 2 + 71 ∗ 5
4、如果最大公约数为1,则可以方便的看出其中一个元素的逆元。上式两端同时模177
71 ∗ 5 ≡ 1 m o d 177
5、这样就得到71和5在Z 177 中 的 逆 元,即5相对于177的逆元是71
(3)求解
求通过不可约多项式x 8
+ x 4 + x 3 + x + 1构造
1.
2.求x 3 + 1在x 8
+ x 4 + x 3 + x + 1上的逆元,构造矩阵
3.行初等变换至标准形式(注意合并多项式的时候系数是模2加法)
4.具体的变换步骤,这里就不详细展开,但给出变换的顺序
- r 1 − x 5 r 2
- r 1 − x 2 r 2
- r 1 − x r 2
- r 1 − r 2
- r 2 − x r 1
- r 1 − x 2 r 2
5.最后得到:
即:1 = x.m(x) + (x6 + x3 + x2 + x + 1).( x3 + 1)
6.显然x 3 + 1的逆元为x 6
+ x 3 + x 2 + x + 1 ,转换为2进制表示01001111,16进制表示
辗转相除法#
求:
参考#
1、扩展欧几里得算法
作者:Hang Shao
出处:https://www.cnblogs.com/pam-sh/p/13722831.html
版权:本作品采用「知识共享」许可协议进行许可。
声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)