diff --git a/src/Advanced/Fast Inverse Root/main.typ b/src/Advanced/Fast Inverse Root/main.typ index 89343db..361ef89 100644 --- a/src/Advanced/Fast Inverse Root/main.typ +++ b/src/Advanced/Fast Inverse Root/main.typ @@ -1,9 +1,5 @@ #import "@local/handout:0.1.0": * -// Another look: -// - Highlight that left-shift divides the exponent by two -// - Highlight that log(ri) is already in its integer representation -// // Bonus: // - Floats vs fixed point // - Float density diff --git a/src/Advanced/Fast Inverse Root/parts/01 float.typ b/src/Advanced/Fast Inverse Root/parts/01 float.typ index 0d9ec5e..1125a1f 100644 --- a/src/Advanced/Fast Inverse Root/parts/01 float.typ +++ b/src/Advanced/Fast Inverse Root/parts/01 float.typ @@ -128,7 +128,7 @@ Find the $s$, $E$, and $F$ we get if we interpret this bit string as a `float`. #v(1fr) -#definition() +#definition(label: "floatdef") The final value of a float with sign $s$, exponent $E$, and fraction $F$ is $ diff --git a/src/Advanced/Fast Inverse Root/parts/03 quake.typ b/src/Advanced/Fast Inverse Root/parts/03 quake.typ index c5222fb..f2b96ae 100644 --- a/src/Advanced/Fast Inverse Root/parts/03 quake.typ +++ b/src/Advanced/Fast Inverse Root/parts/03 quake.typ @@ -162,8 +162,6 @@ So, $0.045$ is the $epsilon$ used by Quake. \ Online sources state that this constant was generated by trial-and-error, \ though it is fairly close to the ideal $epsilon$. -#v(4mm) - #remark() And now, we're done! \ We've shown that `Q_sqrt(x)` approximates $1/sqrt(x)$ fairly well, \ @@ -172,9 +170,39 @@ thanks to the approximation $log(1+a) = a + epsilon$. #v(2mm) Notably, `Q_sqrt` uses _zero_ divisions or multiplications (`>>` doesn't count). \ -This makes it _very_ fast when compared to more traditional approximation techniques like Fourier series. +This makes it _very_ fast when compared to more traditional approximation techniques (i.e, Taylor series). #v(2mm) In the case of _Quake_, this is very important. 3D graphics require thousands of inverse-square-root calculations to render a single frame#footnote[e.g, to generate normal vectors], which is not an easy task for a Playstation running at 300MHz. +#instructornote[ + Let $x$ be a bit string. If we assume $x_f$ is positive and $E$ is even, then + $ + (x #text[`>>`] 1)_f = 2^((E div 2) - 127) times (1 + (F div 2) / (2^(23))) + $ + Notably: a right-shift divides the exponent of $x_f$ by two, \ + which is, of course, a square root! + + #v(2mm) + + This intuition is hand-wavy, though: \ + If $E$ is odd, its lowest-order bit becomes the highest-order bit of $F$ when we shift $x$ right. \ + Also, a right shift doesn't divide the _entire_ exponent, skipping the $-127$ offset. \ + + #v(2mm) + + Remarkably, this intuition is still somewhat correct. \ + The bits align _just so_, and our approximation still works. + + #v(8mm) + + One can think of the fast inverse root as a "digital slide rule": \ + The integer representation of $x_f$ already contains $log_2(x_f)$, offset and scaled. \ + By subtracting and dividing in "log space", we effectively invert and root $x_f$! + + After all, + $ + - 1 / 2 log_2(n_f) = 1 / sqrt(n_f) + $ +]