密次运算问题

Herb2 2009-06-11 04:04:11
求y=(a^b) % n
也就a的b次方然后对n取模运算。
比如 y=(2^3) % 5
= 8 % 5
= 3
再比如 y=(3^3) % 7
= 27 % 7
= 6

只是目前的a,b,和n都很大
a,b,n 都 大于2^32 但小于 2^64
a^b 大于 2^64
n^2 大于 2^64
超出了长整数范围。

如何计算。
...全文
205 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
fairchild811 2009-06-13
  • 打赏
  • 举报
回复
用字符串存吧,每个位置对应一个数字
baihacker 2009-06-13
  • 打赏
  • 举报
回复
呵...
ToBeTough 2009-06-13
  • 打赏
  • 举报
回复
学习
孤独剑客 2009-06-13
  • 打赏
  • 举报
回复
路过
zhouzhi733 2009-06-12
  • 打赏
  • 举报
回复
试试 分段进行取摸 在进行运算 呢 
baihacker 2009-06-12
  • 打赏
  • 举报
回复
a * a在2 ^ 64以内.
应该是2 ^ 128

假设是1万进制.
for (int i = 最高位;i >= 0; ans = (ans * 10000 + data[i--]) % p);
这是大数取模的算法.

typedef struct BigNum_
{
int len;
int data[1005];
int sign;
} BigNum;
void Mul(BigNum* result ,BigNum* l, BigNum* r)
{
int i, j;
int len = -1;
int * d1 = l->data;
int * d2 = r->data;
int * d3 = result->data;
for (i = 0; i < r->len; ++i)
{
int k = d2[i];
int weight = 0;
for (j = 0; j < l->len; ++j)
{
weight += k * d1[j] + d3[j+i];
d3[j+i] = weight % 10000;
weight /= 10000;
}
while (weight) d3[j+++i] = weight%10000, weight/=10000;
if (j+i > len) len = j+i;
}
result->sign = l->sign * r->sign;
result->len = len;
}
这是一万进制下,大数乘法...
速度比较快.
baihacker 2009-06-12
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 Herb2 的回复:]
我这里关键其实是解决大数乘法问题,在我的问题中已经说的很清楚,
已知:
2^32 < a < b < n < 2^64
极端情况会出现
2^63 < a < b < n < 2^64


所以上面a*a 已经超出了范围,甚至有可能a+a超过2^64.

那么 12L 18L都难以满足要求。

19L 提到了大数运算,但如果几样运算,是不是时间上不允许。

22楼的我看不太明白。
[/Quote]
由于n < 2 ^ 64
所以在计算过程中a,b,都可以保证在2^64以内
a * a在2 ^ 64以内.
你可以直接实现一个大数.
也可以用两个long long模拟128位整数啊...

不过,模拟的速度比较慢,而且不能完全模拟.因为为了显示方便,要用10的19方的进制.

用三个long long,用数组模拟大数,足矣.
C_Plus87 2009-06-12
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 baihacker 的回复:]
C/C++ code
x的y次方对p求模.
inline long long PowerMod(long long x, long long y, long long p)
{
long long result = 1;
for (;y; y /= 2, x = x * x % p) if (y&1) result = (result * x) % p;
return result;
}
[/Quote]

第一次见到这种用法,学习了
baihacker 2009-06-12
  • 打赏
  • 举报
回复

x的y次方对p求模.
inline long long PowerMod(long long x, long long y, long long p)
{
long long result = 1;
for (;y; y /= 2, x = x * x % p) if (y&1) result = (result * x) % p;
return result;
}
qiyudong 2009-06-12
  • 打赏
  • 举报
回复
你搜一下模平方根重复取余法吧,这可能会有用。
光宇广贞 2009-06-12
  • 打赏
  • 举报
回复
18 楼的方法就是算 a^b mod n 的最高效的算法。

楼主只要解决掉一步 __int64 FuckAgain ( __int64 a, __int64 b, __int64 n ); // 计算 (a * b ) % n

就可以了。
光宇广贞 2009-06-12
  • 打赏
  • 举报
回复
使用“平方探测”法就可以解决。

不过对于大于32位的数儿来说,一次平方很可能超过 __int64,关键就在一步 d = ( d * a ) % n 怎么解决,因为 d * a 很可能超过了 __int64。

算法其实挺简单的:


UINT Fuck ( UINT a, UINT b, UINT n )
{
UINT d = 1;

while ( b )
{
if ( b & 1 ) d = ( d * a ) % n;
b >>= 1;
a = ( a * a ) % n;
}

return d;
}


但这里如何把 UINT 换成 ULL,解决掉 d = ( d * a ) % n 和 a = ( a * a ) % n 就可以。
可以通过内联汇编来解决大数相乘的问题。或者写一个函数来处理大数相乘,这个比较好找,因为最后要模 n ,所以结果还是会控制在 __int64 之内的。
  • 打赏
  • 举报
回复
[Quote=引用楼主 Herb2 的帖子:]
求y=(a^b) % n
也就a的b次方然后对n取模运算。
比如 y=(2^3) % 5
= 8 % 5
= 3
再比如 y=(3^3) % 7
= 27 % 7
= 6

只是目前的a,b,和n都很大
a,b,n 都 大于2^32 但小于 2^64
a^b 大于 2^64
n^2 大于 2^64
超出了长整数范围。

如何计算。
[/Quote]

楼主是想做DH算法?

如果你想支持远大于32位的运算,那没办法只能用大数库。
用gmp库就可以了。

此外还是可以做出一点改进,不需要算出(a^b)再求余。
我的博客有说过

http://blog.csdn.net/hairetz/archive/2009/04/30/4140571.aspx
pathuang68 2009-06-12
  • 打赏
  • 举报
回复
Herb2 2009-06-12
  • 打赏
  • 举报
回复
我这里关键其实是解决大数乘法问题,在我的问题中已经说的很清楚,
已知:
2^32 < a < b < n < 2^64
极端情况会出现
2^63 < a < b < n < 2^64


所以上面a*a 已经超出了范围,甚至有可能a+a超过2^64.

那么 12L 18L都难以满足要求。

19L 提到了大数运算,但如果几样运算,是不是时间上不允许。

22楼的我看不太明白。
iamyujulong 2009-06-12
  • 打赏
  • 举报
回复
可以使用二分求幂
时间复杂度 O(logb)
int64 mod(int64 a,int64 b,int64 n)
{
int64 z;
while( b )
{
z = mymod( mutiply(a,z), n ) ;
b/=2;
a = mymod( mutiply(a,a), n );
}
return z;
}
用java写我觉得比较方便
如果非要用C++
typedef string int64
剩下就完成上面模块:mymod(),mutiply();
楼主如果要的话,我可以给你。。
iamyujulong 2009-06-12
  • 打赏
  • 举报
回复
楼主能给n的范围吗?
liao05050075 2009-06-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 goodname 的回复:]
我的意思是说没连成几次之后再mod一下

比如说对于x=2,b=1000;
则x乘以10次后mod一下,成为y,则只需计算
y,b=100;

如此下去
[/Quote]

这个算法是对的。不过时间上是不行的。
因为a,b,n 都 大于2^32 但小于 2^64
所以,O(b)的复杂度是不能接受的。
ameyume 2009-06-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 goodname 的回复:]
我的意思是说没连成几次之后再mod一下

比如说对于x=2,b=1000;
则x乘以10次后mod一下,成为y,则只需计算
y,b=100;

如此下去
[/Quote]
这是这个方法
goodname 2009-06-11
  • 打赏
  • 举报
回复
总的来说第一步
a mod n = x
然后
x*x mod n;
c = b/2+b%2
x*x = y

再计算
y^c

如此一直到c=1
加载更多回复(12)

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧