From 8f4bbff55064f20121bc949e3e1c5f763f5c685f Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 9 Feb 2025 21:58:41 -0800 Subject: [PATCH] More edits --- .../Fast Inverse Root/parts/02 approx.typ | 182 ++++++++++++------ .../Fast Inverse Root/parts/03 quake.typ | 7 +- 2 files changed, 134 insertions(+), 55 deletions(-) diff --git a/src/Advanced/Fast Inverse Root/parts/02 approx.typ b/src/Advanced/Fast Inverse Root/parts/02 approx.typ index 0ed9211..7bd75b6 100644 --- a/src/Advanced/Fast Inverse Root/parts/02 approx.typ +++ b/src/Advanced/Fast Inverse Root/parts/02 approx.typ @@ -5,67 +5,141 @@ = Integers and Floats #generic("Observation:") -For small values of $a$, $log_2(1 + a)$ is approximately equal to $a$. \ -Note that this equality is exact for $a = 0$ and $a = 1$, since $log_2(1) = 0$ and $log_2(2) = 1$. - -#v(2mm) - -We'll add a "correction term" $epsilon$ to this approximation, so that $log_2(1 + a) approx a + epsilon$. - -#cetz.canvas({ - import cetz.draw: * - - let f1(x) = calc.log(calc.abs(x + 1), base: 2) - let f2(x) = x - - // Set-up a thin axis style - set-style(axes: (stroke: .5pt, tick: (stroke: .5pt))) - - - plot.plot( - size: (8, 8), - x-tick-step: 0.2, - y-tick-step: 0.2, - y-min: 0, - y-max: 1, - x-min: 0, - x-max: 1, - legend: none, - axis-style: "scientific-auto", - - { - let domain = (0, 10) - - plot.add-fill-between( - f1, - f2, - domain: domain, - style: (stroke: none, fill: luma(75%)), - ) - - plot.add( - f1, - domain: domain, - label: $log(1+x)$, - style: (stroke: black), - ) - plot.add(f2, domain: domain, label: $x$, style: (stroke: black)) - }, - ) -}) - -TODO: why? Graphs. - -#problem(label: "convert") -Use the fact that $log_2(1 + a) approx a + epsilon$ to approximate $log_2(x_f)$ in terms of $x_i$. \ +For small values of $x$, $log_2(1 + x)$ is approximately equal to $x$. \ +Note that this equality is exact for $x = 0$ and $x = 1$, since $log_2(1) = 0$ and $log_2(2) = 1$. #v(5mm) +We'll add the _correction term_ $epsilon$ to our approximation: $log_2(1 + a) approx a + epsilon$. \ +This allows us to improve the average error of our linear approximation: + +#table( + stroke: none, + align: center, + columns: (1fr, 1fr), + inset: 5mm, + [$log(1+x)$ and $x + 0$] + + cetz.canvas({ + import cetz.draw: * + + let f1(x) = calc.log(calc.abs(x + 1), base: 2) + let f2(x) = x + + // Set-up a thin axis style + set-style(axes: (stroke: .5pt, tick: (stroke: .5pt))) + + + plot.plot( + size: (7, 7), + x-tick-step: 0.2, + y-tick-step: 0.2, + y-min: 0, + y-max: 1, + x-min: 0, + x-max: 1, + legend: none, + axis-style: "scientific-auto", + x-label: none, + y-label: none, + { + let domain = (0, 1) + + plot.add( + f1, + domain: domain, + label: $log(1+x)$, + style: (stroke: ogrape), + ) + + plot.add( + f2, + domain: domain, + label: $x$, + style: (stroke: oblue), + ) + }, + ) + }) + + [ + Max error: 0.086 \ + Average error: 0.0573 + ], + [$log(1+x)$ and $x + 0.045$] + + cetz.canvas({ + import cetz.draw: * + + let f1(x) = calc.log(calc.abs(x + 1), base: 2) + let f2(x) = x + 0.0450466 + + // Set-up a thin axis style + set-style(axes: (stroke: .5pt, tick: (stroke: .5pt))) + + + plot.plot( + size: (7, 7), + x-tick-step: 0.2, + y-tick-step: 0.2, + y-min: 0, + y-max: 1, + x-min: 0, + x-max: 1, + legend: none, + axis-style: "scientific-auto", + x-label: none, + y-label: none, + { + let domain = (0, 1) + + plot.add( + f1, + domain: domain, + label: $log(1+x)$, + style: (stroke: ogrape), + ) + + plot.add( + f2, + domain: domain, + label: $x$, + style: (stroke: oblue), + ) + }, + ) + }) + + [ + Max error: 0.041 \ + Average error: 0.0254 + ], +) + + +A suitiable value of $epsilon$ can be found using calculus or with computational trial-and-error. \ +We won't bother with this---we'll simply leave the correction term as an opaque constant $epsilon$. + + + +#v(1fr) + +#note( + type: "Note", + [ + "Average error" above is simply the area of the region between the two graphs: + $ + integral_0^1 abs( #v(1mm) log(1+x) - (x+epsilon) #v(1mm)) + $ + Feel free to ignore this note, it isn't a critical part of this handout. + ], +) + + +#pagebreak() + +#problem(label: "convert") +Use the fact that $log_2(1 + a) approx a + epsilon$ to approximate $log_2(x_f)$ in terms of $x_i$. \ Namely, show that $ log_2(x_f) = (x_i) / (2^23) - 127 + epsilon $ -for some correction term term $epsilon$ \ #note([ In other words, we're finding an expression for $x$ as a float in terms of $x$ as an int. diff --git a/src/Advanced/Fast Inverse Root/parts/03 quake.typ b/src/Advanced/Fast Inverse Root/parts/03 quake.typ index 5689863..85c6192 100644 --- a/src/Advanced/Fast Inverse Root/parts/03 quake.typ +++ b/src/Advanced/Fast Inverse Root/parts/03 quake.typ @@ -4,6 +4,9 @@ The following code is present in _Quake III Arena_ (1999): + +#v(5mm) + ```c float Q_rsqrt( float number ) { long i = * ( long * ) &number; @@ -12,6 +15,8 @@ float Q_rsqrt( float number ) { } ``` +#v(5mm) + This code defines a function `Q_rsqrt` that consumes a float `number` and approximates its inverse square root. If we rewrite this using notation we're familiar with, we get the following: $ @@ -112,7 +117,7 @@ What is the exact value of $kappa$ in terms of $epsilon$? \ #solution[ This problem makes sure our students see that - $kappa = (2^24)/3(epsilon - 127)$. \ + $kappa = 2^23 3/2 (127 - epsilon)$. \ See the solution to @finalb. ]