Skip to main content

Command Palette

Search for a command to run...

Fast Inversed Squareroot Function - Quake 3

Updated
•4 min read•View as Markdown

This technique gained popularity in the early days of computer graphics when processing power was limited. It's an approximation method used to calculate the reciprocal of a square root \(\displaystyle \frac 1 {\sqrt{x}}\) faster than the standard division and square root functions. This was implemented in Quake 3 game.

Bản tiếng Việt ở đây

The source code

float Q_rsqrt(float number)
{
  long i;
  float x2, y;
  const float threehalfs = 1.5F;

  x2 = number * 0.5F;
  y  = number;
  i  = * ( long * ) &y;                       // evil floating point bit level hacking
  i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
  y  = * ( float * ) &i;
  y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
  // y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

  return y;
}

Let's dig into the source code

The IEEE 754 Standard

According to this standard, a float number is represented as 3 parts of 32 bits: Sign bit (x1), Exponential bits (x8), Mantissa bits (x23).
Then, a positive float number $x$ is calculated by: \(x=(1+\frac M {2^{23}})*2^{E-127} \quad (*)\)

And, bit representation of $x$ would be: \(M + 2^{23}*E \quad (**)\)

Extract $x$ binary information from the \(\log_2x​\)

For $x$ small \(x \in [0,1)\), we could approximate $x$ by: \(x \approx \log_2(1+x)\), then we can claim that:

$$\log_2(1+x) = x + \mu; \quad (\mu \text{ is empirically chosen at 0.043})$$

Looking at an arbitrary value $x$, applying (*), we have:

$$\log_2 x = \log_2 \left((1+\frac M {2^{23}})*2^{E-127}\right) = \log_2(1+\frac M {2^{23}}) + E - 127$$

Since \(\displaystyle \frac M {2^{23}} \in [0,1)\), we now apply the approximation rule:

$$\log_2(1 + \frac M {2^{23}}) = \frac M {2^{23}} + \mu$$

Then:

$$\begin{align*} \log_2 x &= \frac M {2^{23}} + \mu + E - 127\\ &= \frac M {2^{23}} + \frac {2^{23} * E} {2^{23}} + \mu - 127 \\ &= \frac 1 {2^{23}}(\underbrace{M + 2^{23}E}_{\text{bit representation (**)}}) + \mu - 127 \end{align*}$$

Calculate \(\frac 1 {\sqrt{x}}\) using \(\log_2​\)

The meaning of the line of code: -(i >>1)

$$\log_2(\frac 1 {\sqrt{x}}) = \log_2(x^{-\frac 1 2}) = -\frac 1 2 \log_2(x)$$

Let \(\Gamma=\frac 1 {\sqrt{x}} \implies \log_2(\Gamma) = \log_2 (\frac 1 {\sqrt{x}}) = -\frac 1 2 \log_2(x)​\)

We replace the logarithm with the bit representation for both sides:

$$\begin{align*} \frac 1 {2^{23}}(M_{\Gamma} + 2^{23}*E_{\Gamma}) + \mu - 127 = -\frac1 2 \left( \frac 1 {2^{23}}(M_x + 2^{23}*E_x) + \mu -127 \right) \\ \iff M_{\Gamma} + 2^{23}E_{\Gamma} = \underbrace{\frac {3} {2} 2^{23}(127-\mu)}_{\text{0x5f3759df}} - \underbrace{\frac 1 2(\underbrace{M_x + 2^{23}*E_x)}{x}}_{i>>1} \end{align*}$$

Here reveals the secret of this line of code:

i  = 0x5f3759df - ( i >> 1 );  // what the fuck?

Newton Iteration Method for Finding Approximation of Root

$$\boxed{x_{new} = x_{old} - \frac {f(x)} {f' (x)}}$$

Let \(\displaystyle f(y)=\frac 1 {y^2} - x\), then: \(\displaystyle f(y)=0 \iff y=\frac 1 {\sqrt{x}}\). We try to solve \(f(y)=0\) using Newton-Ralphson method. First we compute the derivative of $f(y)$:

$$f'(y) = \frac {y-xy^3} {-2}$$

Then

$$y_{new} = y - \frac {f(y)}{f' (y)} = y - \frac {y-xy^3} {-2} = y(\frac 3 2 - \frac x 2 y^2)$$

This is the meaning of the last line of code:

 y  = y * ( threehalfs - ( x2 * y * y ) );

Demo & JS Code

JS Code

function fastInverseSqrt(x) {
            const threeHalfs = 1.5;

            let i = new Float32Array(1);
            let y = new Float32Array(1);

            y[0] = x;

            i = new Int32Array(y.buffer); // Reinterprets the bits as an integer
            i[0] = 0x5f3759df - (i[0] >> 1); // Magic number and bit shift

            y = new Float32Array(i.buffer); // Reinterpret the bits back to float
            y[0] = y[0] * (threeHalfs - (x * 0.5 * y[0] * y[0])); // First iteration of Newton's method
            y[0] = y[0] * (threeHalfs - (x * 0.5 * y[0] * y[0])); 

            return y[0];
        }

More from this blog

L

Legos' writes and shares

49 posts

...interesting things by short notes and demos. Most of notes are in Vietnamese since too few of resources of the language and machine translation EN-VN are not good enough :)