对于此函数,计算最多的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)
exp2(n)返回一个double.
在IEEE754(一种非常常见的浮点类型规范)中,它只能为您提供高达52次方2的精确整数.此后,您将获得近似值.
您在第52个Woodall数之前观察问题,因为整个表达式n * (exp2(n))) - 1是double由于隐式类型转换.通过计算怪癖,导致问题的是-1.只是碰巧另一个术语是2的幂的适当倍数,它允许它表示为双精度而没有精度损失!这是你的第二个片段工作背后的原因,但你的第一个片段没有.
在具有64位的系统上int,您将在第63次幂为2时达到整数限制(和未定义的行为).
你最好的选择是纯粹用unsigned算术生成Woodall数(注意<<2和2的幂之间的关系),甚至可能使用连续Woodall数的递推关系.