快速求平方根倒数的算法(通常被称为“快速逆平方根”或“Fast Inverse Square Root”,也被称为“0x5f3759df”算法)是一个在早期的计算机图形学(特别是在3D渲染中)中广泛使用的技巧,用于快速近似地计算一个浮点数的平方根倒数。若要求取照明和投影的波动角度与反射效果,就常需计算平方根倒数。这个算法最初是在Intel的3D渲染库中发现的,并因其使用了特定的浮点数表示特性和位操作而著名。
以下是该算法基本的实现方式:
float fast_inverse_square_root(float x) {
float xhalf = 0.5f * x;
int i = *(int*)&x; // 将浮点数转换为整数,以获取其位表示
i = 0x5f3759df - (i >> 1); // 使用特定的“魔数”0x5f3759df和位操作进行近似
x = *(float*)&i; // 将整数转换回浮点数
x = x * (1.5f - xhalf * x * x); // 进行一次或多次牛顿迭代以提高精度
return x;
}
这个算法的工作原理是基于IEEE 754浮点数标准的二进制表示。通过将浮点数视为整数,并使用特定的“魔数”(在这种情况下是0x5f3759df),算法可以生成一个接近实际平方根倒数的初始近似值。然后,它使用牛顿迭代法来进一步提高这个近似值的精度。
下面内容是对这个算法的解析。如果你觉得看文字很麻烦,可以看这个博主的视频解说,我最开始也是从这个视频了解到这个神奇算法的。
「珂学原理」No.95「骚代码是怎样炼成的」解剖快速平方根倒数算法
浮点数
众所周知,32位浮点数是这样存储在计算机中的:
即:1位符号位(sign),8位指数位(exponent),23位尾数(mantissa),指数被偏置127以适应正指数和负指数,尾数不存储前导1
对于浮点数x,有
我们将存取之后的8位指数部分用E表示 将存取之后的23位尾数部分用M表示,有如下对应关系
数学推导
所求 两边取对数
①
令②y=
令③x=
联立上面三式化解:
由于的图像近似于一条直线(如上图),我们将上式近似为
令,
,
,
则
我们令为K, 前辈们给出了当 b = 0.0450465时,能够较精确地逼近真实值。有K=0x5f3759df。
令,注意观察,这时候代表的意义就是y看作整型所示的值
同样的,令
则有,
这时候我们才明白了
i = 0x5f3759df - (i >> 1);
这句核心代码的含义。
牛顿迭代
[图片上传失败...(image-8284da-1717424823267)]
但是,需要注意的是,这个算法并不是在所有情况下都能提供准确的结果,并且其精度可能会受到浮点数表示的限制。因此,在需要高精度结果的应用中,最好使用标准的数学库函数(如1.0 / sqrt(x))来计算平方根倒数。