我遇到一个问题,我给出了一个名为N的T号列表(T是输入的第一行),我必须为每个号码打印((2^N)-1)%(10^9+7)
。以下限制适用:
1 ≤ T ≤ 100
1 ≤ N ≤ 100000000
我得到的是低整数的正确答案,但不适用于高整数。我认为这与math.h中的pow()
函数有关,但我不确定。
这是我的代码:
#include <stdio.h>
#include <math.h>
int main(void) {
unsigned int t, i;
long long unsigned int ans, n, m = 1000000007;
scanf("%u", &t);
for (i = 0; i < t; ++i) {
scanf("%llu", &n);
ans = ((long long unsigned int)pow(2,n)-1)%m;
printf("%llu\n", ans);
}
return 0;
}
所以基本上当我给我的程序这个输入时:
6
1
2
3
4
5
100000000
我得到了输出:
1
3
7
15
31
582344007
我的输出的前5行是正确的,但我想得到最后一行494499947。
See here for the wolfram alpha output which gives the correct answer.
对不起,如果我的问题很简单,我还在学习C的详细信息。
答案 0 :(得分:4)
pow(2, 100000000)
的结果超过3000万位数。它无法转换为整数类型(即使long long unsigned int
) - 它太大了!
您需要使用modular exponentiation来获得准确的结果。
答案 1 :(得分:1)
您的方法非常耗时,大小超过2 ^ 64(很长很长)。 正如你的问题中所说,你想要找到2 ^ 100000000。精确地 O(n)需要“100000000”这么多次迭代。 因此更好的方法是使用模幂运算。 它不仅在 O(log n)时间计算,而且在中间步骤使用mod 10 ^ 9 + 7给出整数(long long)范围的答案。
mod=10^9+7;
powermod(x,y)
res:=1
while(y>0)
if y&1
res=res*x%mod
x=x*x%mod
y=y>>1
return res
答案 2 :(得分:0)
你正在调用pow,这需要一倍。如果你想要最大范围,至少在Linux上使用powl,这需要很长的时间。 您的程序缺少检查溢出,范围错误等。如果(似乎)您对结果的正确性感兴趣,那么您应该添加这些。 我想你只需要更仔细地阅读'man pow': - )