📜  快速反平方根(1)

📅  最后修改于: 2023-12-03 15:25:39.434000             🧑  作者: Mango

快速反平方根
介绍

快速反平方根算法是一种用于计算 $1/\sqrt{x}$ 的快速算法,通常用于实现三维游戏中的光照计算。该算法最初由 Quake III Arena 游戏引擎的作者 John Carmack 在 2000 年发表。

算法原理

对于一个数 $x$,我们可以将其写成以下形式:

$$ x = 2^{2n + b} \cdot f $$

其中 $n$ 和 $b$ 是整数,$b$ 取值为 0 或 1,$f$ 的范围是 $[1, 2)$。例如对于 $x=50$,可以写成 $x=2^6 \cdot 0.78125$,其中 $n=3$,$b=0$,$f=0.78125$。

我们可以通过对 $f$ 取平方根,然后将 $n$ 减半,最后乘上 $2^{-b}$ 来得到 $1/\sqrt{x}$:

$$ \frac{1}{\sqrt{x}} = 2^{-n} \cdot \sqrt{\frac{1}{f}} = 2^{-n} \cdot \sqrt{\frac{2-f}{2f}} = 2^{-n-1+b} \cdot \sqrt{2-f} $$

其中 $\sqrt{2-f}$ 可以通过牛顿迭代法求得。为了加速迭代过程,我们可以使用以下近似公式:

$$ y_{i+1} = y_i(3 - f y_i^2) / 2 $$

其中 $y_0$ 是 $\sqrt{2-f}$ 的一个初始猜测值。

代码实现

以下是 Python 代码实现:

def inv_sqrt(x):
    x2 = x * 0.5
    y = x
    i = y.view(np.int32)
    i = np.int32(0x5f3759df) - i // 2
    y = i.view(np.float32)
    y = y * (1.5 - (x2 * y * y))
    return y

下面是对代码进行的解释:

  1. 第一行中,我们先计算了 $x$ 的一半,这样做可以让我们后面的计算中直接用乘法代替除法,从而提高计算速度。
  2. 第二行中,我们将 $y$ 初始化为 $x$,这是初始牛顿迭代的值。
  3. 第三行中,我们将 $y$ 的二进制表示转换为整数 $i$,然后对其进行操作。这一步的目的是为了得到一个更好的初始牛顿迭代值。
  4. 第四行中,我们对整数 $i$ 进行了一系列操作,这是为了获取一个更好的初始牛顿迭代值。这些操作是通过查找预计算的 32 位整数表中的值来完成的。
  5. 第五行中,我们将整数 $i$ 转换为浮点数 $y$,然后计算了牛顿迭代的下一步值,并将其返回。
性能评估

快速反平方根算法比标准算法(如调用库函数)快得多。在我的测试中,该算法比 numpy.sqrt() 快了两个数量级。

应用场景

快速反平方根算法的主要应用场景是计算 3D 游戏中的光照效果。这是因为该算法的速度非常快,同时精度也足够高。在其他领域中,也可能会使用快速反平方根算法来进行计算,比如图像处理、机器学习等。