在n> 47之后,为什么我的计算woodall数字的程序会产生错误的结果?

tig*_*ger 2 c++ math icc

对于此函数,计算最多的woodall数 n = 64

并且该算法用于伍德尔为W ñ = N⋅2 Ñ - 1

for (int n = 1; n <= 64; ++n)
{
    a[n - 1] = (n * (exp2(n))) - 1;
}
Run Code Online (Sandbox Code Playgroud)

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

如果我cout是值via,那么输出是什么

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
Run Code Online (Sandbox Code Playgroud)

......之后是不正确的

for a[]是一个unsigned 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;
}
Run Code Online (Sandbox Code Playgroud)

Bat*_*eba 5

exp2(n)返回一个double.

在IEEE754(一种非常常见的浮点类型规范)中,它只能为您提供高达52次方2的精确整数.此后,您将获得近似值.

您在第52个Woodall数之前观察问题,因为整个表达式n * (exp2(n))) - 1double由于隐式类型转换.通过计算怪癖,导致问题的是-1.只是碰巧另一个术语是2的幂的适当倍数,它允许它表示为双精度而没有精度损失!这是你的第二个片段工作背后的原因,但你的第一个片段没有.

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

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