“魔法”计算反平方根的方法据说可以追溯到Quake游戏时期,已经在许多来源中被描述。维基百科有一篇很好的文章介绍它: https://en.wikipedia.org/wiki/Fast_inverse_square_root
我特别认为下面这篇对该算法进行了非常好的阐述和分析:https://cs.uwaterloo.ca/~m32rober/rsqrt.pdf
我正在尝试按照这篇论文中的某些结果进行复制,但是存在精度问题。该算法使用C语言编写,如下所示:
输出结果为:
#include <math.h>
#include <stdio.h>
float Q_rsqrt(float number) {
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = *(long *) &y;
i = 0x5f3759df - (i >> 1);
y = *(float *) &i;
y = y * (threehalfs - (x2 * y * y));
// y = y * (threehalfs - (x2 * y * y));
return y;
}
这篇论文指出,对于所有正常浮点数,相对误差最大为0.0017522874
(请参见附录2中的代码以及第1.4节中的讨论)。
然而,当我“插入”数字1.4569335e-2F
时,得到的误差大于预测的容差:
int main ()
{
float f = 1.4569335e-2F;
double tolerance = 0.0017522874;
double actual = 1.0 / sqrt(f);
float magic = Q_rsqrt(f);
double err = fabs (sqrt(f) * (double) magic - 1);
printf("Input : %a\n", f);
printf("Actual : %a\n", actual);
printf("Magic : %a\n", magic);
printf("Err : %a\n", err);
printf("Tolerance: %a\n", tolerance);
printf("Passes : %d\n", err <= tolerance);
return 0;
}
输出结果为:
Input : 0x1.dd687p-7
Actual : 0x1.091cc953ea828p+3
Magic : 0x1.08a5dcp+3
Err : 0x1.cb5b716b7b6p-10
Tolerance: 0x1.cb5a044e0581p-10
Passes : 0
所以,这个特定的输入似乎违反了那篇论文中提出的声明。
我想知道这是否是论文本身存在的问题,还是我的编码有误。我会非常感激任何反馈!