
Fast inverse square root, sometimes referred to as or by the hexadecimal constant , is an algorithm that estimates , the reciprocal (or multiplicative inverse) of the square root of a 32-bit floating-point number
x
rsqrtss, this algorithm is not generally the best choice for modern computers, though it remains an interesting historical example.The algorithm accepts a 32-bit floating-point number as the input and stores a halved value for later use. Then, treating the bits representing the floating-point number as a 32-bit integer, a logical shift right by one bit is performed and the result subtracted from the number, which is a floating-point representation of an approximation of . This results in the first approximation of the inverse square root of the input. Treating the bits again as a floating-point number, it runs one iteration of Newton's method, yielding a more precise approximation.
William Kahan and K.C. Ng at Berkeley wrote an unpublished paper in May 1986 describing how to calculate the square root using bit-fiddling techniques followed by Newton iterations. In the late 1980s, Cleve Moler at Ardent Computer learned about this technique and passed it along to his coworker Greg Walsh. Greg Walsh devised the now-famous constant, and fast inverse square root algorithm. Gary Tarolli was consulting for Kubota, the company funding Ardent at the time, and likely brought the algorithm to 3dfx Interactive circa 1994.
Jim Blinn demonstrated a simple approximation of the inverse square root in a 1997 column for IEEE Computer Graphics and Applications. Reverse engineering of other contemporary 3D video games uncovered a variation of the algorithm in Activision's 1997 Interstate '76.[1]
Quake III Arena, a first-person shooter video game, was released in 1999 by id Software and used the algorithm. Brian Hook may have brought the algorithm from 3dfx to id Software. A discussion of the code appeared on the Chinese developer forum CSDN in 2000, and Usenet and the gamedev.net forum spread the code widely in 2002 and 2003. Speculation arose as to who wrote the algorithm and how the constant was derived; some guessed John Carmack. Quake IIIs full source code was released at QuakeCon 2005, but provided no answers. The authorship question was resolved in 2006 when Greg Walsh, the original author, contacted Beyond3D after their speculation gained popularity on Slashdot.
In 2007 the algorithm was implemented in some dedicated hardware vertex shaders using field-programmable gate arrays (FPGA).[2]
The inverse square root of a floating point number is used in digital signal processing to normalize a vector, scaling it to length 1 to produce a unit vector. For example, computer graphics programs use inverse square roots to compute angles of incidence and reflection for lighting and shading. 3D graphics programs must perform millions of these calculations every second to simulate lighting. When the code was developed in the early 1990s, most floating point processing power lagged the speed of integer processing. This was troublesome for 3D graphics programs before the advent of specialized hardware to handle transform and lighting. Computation of square roots usually depends upon many division operations, which for floating point numbers are computationally expensive. The fast inverse square generates a good approximation with only one division step.
The length of the vector is determined by calculating its Euclidean norm: the square root of the sum of squares of the vector components. When each component of the vector is divided by that length, the new vector will be a unit vector pointing in the same direction. In a 3D graphics program, all vectors are in three-dimensional space, so
\boldsymbolv
(v1,v2,v3)
\|\boldsymbol{v}\|=
| 2} | |
| \sqrt{v | |
| 3 |
\begin{align} \boldsymbol{\hat{v}}&=
| 1 | |
| \left\|\boldsymbol{v |
\right\|}\boldsymbol{v}\\ &=
| 1 | |
| \sqrt{v |
| 2}\boldsymbol{v}, \end{align} | |
| 3 |
| 2 | |
| v | |
| 3 |
At the time, floating-point division was generally expensive compared to multiplication; the fast inverse square root algorithm bypassed the division step, giving it its performance advantage.
The following C code is the fast inverse square root implementation from Quake III Arena, stripped of C preprocessor directives, but including the exact original comment text:
At the time, the general method to compute the inverse square root was to calculate an approximation for , then revise that approximation via another method until it came within an acceptable error range of the actual result. Common software methods in the early 1990s drew approximations from a lookup table. The key of the fast inverse square root was to directly compute an approximation by utilizing the structure of floating-point numbers, proving faster than table lookups. The algorithm was approximately four times faster than computing the square root with another method and calculating the reciprocal via floating-point division. The algorithm was designed with the IEEE 754-1985 32-bit floating-point specification in mind, but investigation from Chris Lomont showed that it could be implemented in other floating-point specifications.
The advantages in speed offered by the fast inverse square root trick came from treating the 32-bit floating-point word[3] as an integer, then subtracting it from a "magic" constant, . This integer subtraction and bit shift results in a bit pattern which, when re-defined as a floating-point number, is a rough approximation for the inverse square root of the number. One iteration of Newton's method is performed to gain some accuracy, and the code is finished. The algorithm generates reasonably accurate results using a unique first approximation for Newton's method; however, it is much slower and less accurate than using the SSE instruction rsqrtss on x86 processors also released in 1999.
As an example, the number
x=0.15625
0011_1110_0010_0000_0000_0000_0000_0000 Bit pattern of both x and i 0001_1111_0001_0000_0000_0000_0000_0000 Shift right one position: (i >> 1) 0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF 0100_0000_0010_0111_0101_1001_1101_1111 The result of 0x5F3759DF - (i >> 1)
Interpreting as IEEE 32-bit representation:
0_01111100_01000000000000000000000 1.25 × 2−3 0_00111110_00100000000000000000000 1.125 × 2−65 0_10111110_01101110101100111011111 1.432430... × 263 0_10000000_01001110101100111011111 1.307430... × 21
Reinterpreting this last bit pattern as a floating point number gives the approximation
y=2.61486
y=2.52549
See main article: Type punning. According to the C standard, reinterpreting a floating point value as an integer by casting then dereferencing the pointer to it can cause undefined behavior in case the sizes of integer and float do not match on the given architecture. This can be avoided by using alternative type punning techniques such as C's unions or C++20's std::bit_cast.[4]
The algorithm computes by performing the following steps:
x
See main article: Single-precision floating-point format.
x
x
\begin{align} x&=\pm1.b1b2b3\ldots x
| ex | |
| 2 |
\end{align}
where the exponent is an integer, and is the binary representation of the significand. Since the single bit before the point in the significand is always 1, it does not need be stored. The equation can be rewritten as:
\begin{align} x&=
| Sx | |
| (-1) |
⋅
| ex | |
| 2 |
(1+mx) \end{align}
where means , so
Thus: and .
These fields are then packed, left to right, into a 32-bit container.
As an example, consider again the number
x=0.15625=0.001012
x
and thus, the three unsigned integer fields are:
S=0
E=-3+127=124=0111 11002
M=0.25 x 223=2 097 152=0010 0000 0000 0000 0000 00002
these fields are packed as shown in the figure below:
The number is represented in binary as:
Ix=Sx ⋅ 231+ExL+Mx
Also, since this algorithm works on real numbers, is only defined for . The code thus assumes and
Sx=0
The number, given to calculate the square root, could be rewritten as:
If were to be calculated without a computer or a calculator, a table of logarithms would be useful, together with the identity , which is valid for every base
b
If
x
x=
| ex | |
| 2 |
(1+mx)
then
log2(x)=ex+log2(1+mx)
and since
mx\in[0,1)
log2(1+mx) ≈ mx+\sigma
where
\sigma
\sigma=0
Thus there is the approximation
log2(x) ≈ ex+mx+\sigma.
Interpreting the floating-point bit-pattern of
x
Ix
\begin{align} Ix&=ExL+Mx\\ &=L(ex+B+mx)\\ &=L(ex+mx+\sigma+B-\sigma)\\ & ≈ Llog2(x)+L(B-\sigma). \end{align}
It then appears that
Ix
log2(x)
log2(x)
log2(x) ≈
| Ix | |
| L |
-(B-\sigma).
The calculation of is based on the identity
log2(y)=-\tfrac{1}{2}log2(x)
Using the approximation of the logarithm above, applied to both
x
y
| Iy | |
| L |
-(B-\sigma) ≈ -
| 1 | \left( | |
| 2 |
| Ix | |
| L |
-(B-\sigma)\right)
Iy
Iy ≈ \tfrac{3}{2}L(B-\sigma)-\tfrac{1}{2}Ix
which is written in the code as
The first term above is the magic number
\tfrac{3}{2}L(B-\sigma)=0x5F3759DF
from which it can be inferred that
\sigma ≈ 0.0450466
| 1 | |
| 2 |
Ix
Ix
See main article: Newton's method. The number
y=\tfrac{1}{\sqrt{x}}
\tfrac{1}{y2}-x=0
yn
y
yn+1
yn-\tfrac{f(yn)}{f'(yn)}
f'(yn)
f(y)
yn
\tfrac{1}{y2}-x=0
\begin{align} f(y)&=
| 1 | |
| y2 |
-x\\ f'(y)&=-
| 2 | |
| y3 |
\\ yn+1&=yn-
| f(yn) | |
| f'(yn) |
\\ &=yn+
| \left( | |||||||
| 2 |
| 1 | ||||||
|
-x\right)\\ &=yn\left(
| 3 | |
| 2 |
-
| x | |
| 2 |
| 2\right), \end{align} | |
| y | |
| n |
which is written in the code as
By repeating this step, using the output of the function (
yn+1
y
It is not known precisely how the exact value for the magic number was determined. Chris Lomont developed a function to minimize approximation error by choosing the magic number
R
Jan Kadlec reduced the relative error by a further factor of 2.7 by adjusting the constants in the single Newton's method iteration as well,[8] arriving after an exhaustive search at
A complete mathematical analysis for determining the magic number is now available for single-precision floating-point numbers.[9]
Subsequent additions by hardware manufacturers have made this algorithm redundant for the most part. For example, on x86, Intel introduced the SSE instruction rsqrtss in 1999. In a 2009 benchmark on the Intel Core 2, this instruction took 0.85ns per float compared to 3.54ns for the fast inverse square root algorithm, and had less error.
long reduces the portability of this code on modern systems. For the code to execute properly, [[sizeof]](long) must be 4 bytes, otherwise negative outputs may result. Under many modern 64-bit systems, [[sizeof]](long) is 8 bytes. The more portable replacement is int32_t.Ex
[1,254]
x
x
Sx=0