132 lines
3.7 KiB
TeX
Raw Normal View History

2025-01-22 21:50:31 -08:00
\section{The Fast Inverse Square Root}
The following code is present in \textit{Quake III Arena} (1999):
\lstset{
breaklines=false,
numbersep=5pt,
xrightmargin=0in
}
\begin{lstlisting}[language=C]
float Q_rsqrt( float number ) {
long i = * ( long * ) &number;
i = 0x5f3759df - ( i >> 1 );
return * ( float * ) &i;
}
\end{lstlisting}
2025-02-08 18:22:28 -08:00
This code defines a function \texttt{Q\_rsqrt} that consumes a float named
2025-02-08 14:54:40 -08:00
\texttt{number} and approximates its inverse square root (in other words, \texttt{Q\_rsqrt} computes $1/\sqrt{\texttt{number}}$).
2025-01-22 21:50:31 -08:00
2025-02-08 14:54:40 -08:00
\vspace{2mm}
2025-01-22 21:50:31 -08:00
2025-02-08 18:22:28 -08:00
If we rewrite this using notation we're familiar with, we get the following:
2025-01-22 21:50:31 -08:00
\begin{equation*}
2025-02-08 18:22:28 -08:00
\texttt{Q\_sqrt}(n_f) = 6240089 - (n_i \div 2) \approx \frac{1}{\sqrt{n_f}}
2025-01-22 21:50:31 -08:00
\end{equation*}
2025-02-08 18:22:28 -08:00
\note{
\texttt{0x5f3759df} is $6240089$ in hexadecimal. \par
It is a magic number hard-coded into \texttt{Q\_sqrt}.
}
2025-01-22 21:50:31 -08:00
2025-02-08 14:54:40 -08:00
\vspace{2mm}
2025-02-08 18:22:28 -08:00
Our goal in this section is to understand why this works: \par
2025-02-08 19:53:58 -08:00
\begin{itemize}
\item How does Quake approximate $\frac{1}{\sqrt{x}}$ by simply subtracting and dividing by two?
\item What's special about $6240089$?
\end{itemize}
2025-01-22 21:50:31 -08:00
\problem{}
2025-02-08 14:54:40 -08:00
Using basic log rules, rewrite $\log_2(1 / \sqrt{x})$ in terms of $\log_2(x)$.
2025-01-22 21:50:31 -08:00
\begin{solution}
2025-02-08 14:54:40 -08:00
\begin{equation*}
\log_2(1 / \sqrt{x}) = \frac{-1}{2}\log_2(x)
\end{equation*}
\end{solution}
\vfill
2025-02-08 19:53:58 -08:00
\pagebreak
2025-02-08 14:54:40 -08:00
2025-02-08 19:53:58 -08:00
\generic{Setup:}
We are now ready to show that $\texttt{Q\_sqrt} \approx \frac{1}{\sqrt{n_f}}$. \par
For convenience, let's call the bit string of the inverse square root $r$. \par
In other words,
\begin{equation*}
r_f := \frac{1}{\sqrt{n_f}}
\end{equation*}
This is the value we want to approximate.
2025-01-22 21:50:31 -08:00
2025-02-08 19:53:58 -08:00
\problem{}<finala>
Find an approximation for $\log_2(r_f)$ in terms of $n_i$ and $\varepsilon$ \par
\note{Remember, $\varepsilon$ is the correction constant in our approximation of $\log_2(1 + a)$.}
2025-02-08 14:54:40 -08:00
\begin{solution}
2025-02-08 19:53:58 -08:00
\begin{equation*}
\log_2(r_f)
~=~ \log_2(\frac{1}{\sqrt{n_f}})
~=~ \frac{-1}{2}\log_2(n_f)
~\approx~ \frac{-1}{2}\left( \frac{n_i}{2^{23}} + \varepsilon - 127 \right)
\end{equation*}
\end{solution}
\vfill
\problem{}<finalb>
Let's call the \say{magic number} in the code above $\kappa$, so that
\begin{equation*}
\texttt{Q\_sqrt}(n_f) = \kappa - (n_i \div 2)
\end{equation*}
Use problems \ref{num:convert} and \ref{num:finala} to show that $\texttt{Q\_sqrt}(n_f) \approx r_i$. \par
\begin{solution}
From \ref{convert}, we know that
\begin{equation*}
\log_2(r_f) \approx \frac{r_i}{2^{23}} + \varepsilon - 127
\end{equation*}
\note{
Our approximation of $\log_2(1+a)$ uses a fixed correction constant, \par
so the $\varepsilon$ here is equivalent to the $\varepsilon$ in \ref{finala}.
}
Combining this with the result from \ref{finala}, we get:
2025-01-22 21:50:31 -08:00
\begin{align*}
2025-02-08 19:53:58 -08:00
\frac{r_i}{2^{23}} + \varepsilon - 127
&~\approx~\frac{-1}{2}\left( \frac{n_i}{2^{23}} + \varepsilon - 127 \right) \\
\frac{r_i}{2^{23}}
&~\approx~\frac{-1}{2}\left( \frac{n_i}{2^{23}} \right) + \frac{3}{2}(\varepsilon - 127) \\
r_i
&~\approx~\frac{-1}{2}\left(n_i \right) + 2^{23}\frac{3}{2}(\varepsilon - 127)
~=~ 2^{23}\frac{3}{2}(\varepsilon - 127) - \frac{n_i}{2}
2025-01-22 21:50:31 -08:00
\end{align*}
2025-02-08 19:53:58 -08:00
\vspace{2mm}
This is exactly what we need! If we set $\kappa$ to $\frac{2^{24}}{3}(\varepsilon - 127)$, then
\begin{equation*}
r_i ~\approx~ \kappa - (n_i \div 2) ~=~ \texttt{Q\_sqrt}(n_f)
\end{equation*}
2025-01-22 21:50:31 -08:00
\end{solution}
2025-02-08 14:54:40 -08:00
\vfill
2025-02-08 19:53:58 -08:00
\problem{}
What is the exact value of $\kappa$ in terms of $\varepsilon$? \par
\hint{Look at \ref{finalb}. We already found it!}
\begin{solution}
This problem makes sure our students see that
$\kappa = \frac{2^{24}}{3}(\varepsilon - 127)$. \par
See the soluton to \ref{finalb}.
\end{solution}
\makeatletter
\if@solutions\else
\vspace{2cm}
\fi\makeatother
2025-01-22 21:50:31 -08:00
\pagebreak