对于此函数,计算woodall数字直至n = 64
Woodall的算法为Wn = n⋅2n-1

for (int n = 1; n <= 64; ++n)
{
    a[n - 1] = (n * (exp2(n))) - 1;
}

但是在n大于47之后,结果是错误的,因为似乎忘记了- 1的结果是n * (exp2(n))

如果我通过cout值,这就是输出
std::cout << i << ":\t" << std::setprecision(32) << a[i - 1] << std::endl;
...之前是正确的
n
45:     1583296743997439
46:     3236962232172543
47:     6614661952700415
48:     13510798882111488
49:     27584547717644288
50:     56294995342131200

...之后不正确

for a[]是一个无符号的long int

如果我将- 1操作分离为自己的for循环,则该函数将产生正确的结果:
for (int n = 1; n <= 64; ++n)
{
    a[n - 1] = (n * (exp2(n)));
}


for (int n = 1; n <= 64; ++n)
{
    a[n - 1] = a[n - 1] - 1;
}

最佳答案

exp2(n)返回一个double

在IEEE754(一种非常常见的浮点类型规范)中,它仅给您精确的整数,直到52的2的幂。

由于整个隐式类型转换,整个表达式n * (exp2(n))) - 1double,因此您会在第52 Woodall号之前观察到问题。 通过计算古怪,是导致问题的-1。恰巧另一个项是2的幂的适当倍数,这使其可以表示为没有精度损失的 double ! ,这是第二个代码段正常运行的原因,而第一个代码段无效。

在具有64位int的系统上,您将以63的2的幂来达到整数限制(和未定义的行为)。

最好的选择是纯粹用unsigned算术生成Woodall数(请注意<<与2的幂之间的关系),甚至可能对连续的Woodall数使用递归关系。

关于c++ - 在n> 47之后,为什么我计算woodall数的程序为什么会产生错误的结果?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53266239/

10-11 06:27