求逆元

求整数上乘法逆元#

求 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的逆元,即71

71为 X,即7 * X = 1 mod 26 ,求 X 即可

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

71 = -11,由于 -11 不在Z_q中,故71  = 26 - 11 = 15

方法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)求解GF(28)上的多项式乘法逆元

求通过不可约多项式x 8 + x 4 + x 3 + x + 1构造GF(28)(09)H​在上的乘法逆元。

1.(09)H转换为多项式

(09)H= 00001001 = x 3 + 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进制表示(4F)H

辗转相除法#

求:(x+x2)(11+x+x2)=1+x

参考#

1、扩展欧几里得算法

2、算法学习 之 欧几里得算法和扩展欧几里得算法(二)

作者:Hang Shao

出处:https://www.cnblogs.com/pam-sh/p/13722831.html

版权:本作品采用「知识共享」许可协议进行许可。

声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.

posted @   PamShao  阅读(2345)  评论(11编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu