【发布时间】:2019-05-01 05:36:46
【问题描述】:
我需要一个 C 中的函数来计算 a^n mod q,其中除数 q 被确定为非常大 (15,383,399,235,709,406,497),并且指数 n 可能也一样大。
基于模乘的性质,即(a * b) mod n = ((a mod n) * (b mod n)) mod n,我的尝试如下:
#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = (out * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}
如上面的 main 函数所示,我用底数 3、指数 (189 + 50 * 223) 和除数 15383399235709406497 测试了我的函数 modExp。它给出了输出 3915400295876975163 并带有一些警告
In function ‘findxA’:
findxA.c:17:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:17:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:18:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c:18:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c: In function ‘main’:
findxA.c:34:48: warning: integer constant is so large that it is unsigned [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
findxA.c:34:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
为了验证这个答案,我将结果(由 C 函数给出)与通过评估用 Haskell 编写的表达式 3^(189 + 50 * 223) `mod` 15383399235709406497 给出的输出进行了比较。这个 Haskell 表达式计算为不同的小数,12349118475990906085。我认为是我的 C 函数错了,因为我相信 Haskell 在处理如此大的小数方面做得更好。
如何改进我的 C 函数 modExp?
编辑:我尝试了the first answer of this question. 的选项但是,当我尝试处理 unsigned long long int 的小数时,我已将每个输入和返回类型从 int 切换为 unsigned长长整数。这导致了分段错误。
Edit2:我错误地使用了上面链接中描述的功能。它不会给出分段错误;但它仍然没有输出正确的小数。
【问题讨论】:
-
如果数字变大,这些警告可能是您最小的问题。您可以在数字中添加后缀
ull以将它们标记为unsigned long long
标签: c modulo unsigned-long-long-int