首页
社区
课程
招聘
[求助]关于求Fp上模逆的疑问??
发表于: 2015-4-27 17:29 6003

[求助]关于求Fp上模逆的疑问??

2015-4-27 17:29
6003
我在一本书上看到的扩展欧几里德算法求模逆, 疑问:

x2初始化为0, 当循环第一步时: x2 - q*x1; 当用无符号数运算的话不是下溢了吗?

如果我使用的大数运算是无符号数, 是否还得判断 x2 < (q*x1), 怎么处理变换避免下溢?

-------------------------

输入: 素数p, 和a (1<a<p)
输出: a^-1 mod p

1. u = a; v = p;
2. x1 = 1; x2 = 0;
3. 当 (u!=1) 时, 重复执行:

   3.1  q = v/u, r = v%u, x = x2 - q*x1

   3.2  v = u, u = r, x2 = x1 , x1 = x

4 返回 (x1 mod p)

---------------------------
r 是余数估计漏写了。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
r是什么?算法是不是有点问题,百度百科里有好多,可以研究下。
递归调用还是比较好实现的,说白了就是一个辗转相除法。
2015-4-28 11:19
0
雪    币: 62
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
可以证明两点:
1、x1与x2符号相反;
2、每次迭代,x1,x2符号均变反。

你给的程序只是计算公式的形式化,转化为C语言时需要做一些处理。简单的做法是添加一个标识x1符号的变量。

1. u = a; v = p;
2. x1 = 1; x2 = 0; flag=0;
3. 当 (u!=1) 时, 重复执行:

   3.1  q = v/u, r=v-qu, x = qx1+x2, x2=x1, x1=x;

   3.2  v = u, u = r, flag = flag^1;

4 if(flag==0) return x1%p;
else return (x1+p)%p;

这个程序可以改造成求最大公约数及其表达系数的程序:

x1=1,x2=0,y1=0,y2=1;flag = 0;
while(u)
        {
                q = v/u;
                r = v - q*u;               
                m = x2 + q*x1;
                n = y2 + q*y1;
                flag = flag^1;
               
                v = u;
                u = r;
                x2 = x1;
                x1 = m;
                y2 = y1;
                y1 = n;
        }        
        // ux + vy = d
        *d = v;// 最大公约数
        *x = x2;
        *y = y2;        
       
        return  flag;//返回x的符号位
2015-4-28 11:39
0
雪    币: 62
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
这里使用递归是有风险的,栈消耗与初值相关,难以控制。
2015-4-28 12:00
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
谢谢 publickey,

之所以不用递归 就是性能考虑。
2015-4-29 19:43
0
雪    币: 179
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
上面给出的模逆运算错误, 无符号运算--有的结果对有的结果不对
===============

#include <stdlib.h>
#include <iostream>
using namespace std;

// 无符号运算模逆
unsigned long ModInv(unsigned long A, unsigned long P)
{
    unsigned long u = A, v = P;
    unsigned long x1 = 1, x2 = 0, flag=0;

    unsigned long q, r, x;
    while (u != 1)
    {
        q = v/u; r = v%u; x = q*x1 + x2;

        v = u; u = r; x2 = x1; x1 = x;

        flag = flag^1;
    }

    if (flag == 1) x1 += P;
    return x1%P;
};

// 有符号运算模逆
long long ModInv(long long A, long long P)
{
    long long u = A, v = P;
    long long x1 = 1, x2 = 0;

    long long q, r, x;
    while (u != 1)
    {
        q = v/u; r = v%u; x = x2 - (q*x1);

        v = u; u = r; x2 = x1; x1 = x;
    }

    x1 %= P;
    if (x1 < 0) x1 += P;
    return x1;
};

int main()
{
    cout << "Hello, world" << endl;

////////////////////

    // 65521是素数
    unsigned long x, a, p = 65521;
    long long X, A, P;

     //65521是2字节, a一定也小于2字节, a*a一定小于4字节, 不会溢出.
    for (unsigned i=0; i<20; i++)
    {
        a = rand();
        a %= p;
        A = a;
        P = p;

        cout << "计算: a=" << a << "  p=" << p << endl;
        X = ModInv(A, P);
        A *= X;
        A %= P;
        if (A == 1) cout << "有符号模逆运算成功: " << X << endl;
        else cout << "有符号模逆运算失败: " << X << "  **" << endl;

        x = ModInv(a, p);
        a *= x;
        a %= p;
        if (a == 1) cout << "无符号模逆运算成功: " << x << endl;
        else cout << "无符号模逆运算失败: " << x << "  **" << endl;

        cout << endl;
    }

    return 0;
};

//  x = x2 - (q*x1); 最麻烦的这步
//  如果x1和x2的符号不相等, 可以直接相加.
//  如果x1和x2的符号相等(同为负数或正数), 还要比较大小, 然后大的减小的, 差为正数.
//  希望有更简单的办法
2015-5-3 12:53
0
雪    币: 62
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
最后一步错了。
if (flag == 1) x1 += P;
    return x1%P;

flag=1时,x1是负数,所以应该是p-x1
2015-5-4 10:53
0
雪    币: 62
活跃值: (27)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
你没有理解这个运算,所以才会纠结符号。
这里不好编辑数学符号,难以讲清楚。
2015-5-4 10:57
0
游客
登录 | 注册 方可回帖
返回
// // 统计代码