diff --git a/.gitignore b/.gitignore
index 2e22839..d4ee5df 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ venv
__pycache__
*.ignore
.mypy_cache
+.DS_Store
# Output files
/output
@@ -10,7 +11,7 @@ __pycache__
*.pdf
# TeX build files
-*.synctex.gz*
+*.synctex*
*.latexmk
*.aux
*.out
diff --git a/lib/tex/ormc_handout.cls b/lib/tex/ormc_handout.cls
index 98da07c..832a81b 100755
--- a/lib/tex/ormc_handout.cls
+++ b/lib/tex/ormc_handout.cls
@@ -1,18 +1,3 @@
-% Copyright (C) 2023 Mark (mark@betalupi.com)
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% (at your option) any later version.
-%
-% This program is distributed in the hope that it will be useful,
-% but WITHOUT ANY WARRANTY; without even the implied warranty of
-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-% GNU General Public License for more details.
-%
-% You should have received a copy of the GNU General Public License
-% along with this program. If not, see .
-
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{../../../lib/tex/ormc_handout}[2023/05/29 2.0.2 ORMC Handout]
diff --git a/lib/typst/local/handout/0.1.0/header.typ b/lib/typst/local/handout/0.1.0/header.typ
index a46cc67..21f2b78 100644
--- a/lib/typst/local/handout/0.1.0/header.typ
+++ b/lib/typst/local/handout/0.1.0/header.typ
@@ -44,6 +44,14 @@
by = text(size: 10pt, [Prepared by #by on #date])
}
+ let sub = ()
+ if (by != none) {
+ sub.push(by)
+ }
+ if (subtitle != none) {
+ sub.push(subtitle)
+ }
+
// Main title
align(
center,
@@ -61,8 +69,7 @@
// Title
text(size: 20pt, title),
// Subtitle
- if (by != none) { text(size: 10pt, by) },
- if (subtitle != none) { text(size: 10pt, subtitle) },
+ ..sub,
line(length: 100%, stroke: 0.2mm),
),
),
diff --git a/lib/typst/local/handout/0.1.0/lib.typ b/lib/typst/local/handout/0.1.0/lib.typ
index 06eddc9..43e503e 100755
--- a/lib/typst/local/handout/0.1.0/lib.typ
+++ b/lib/typst/local/handout/0.1.0/lib.typ
@@ -3,8 +3,14 @@
// Re-exports
// All functions that maybe used by client code are listed here
#import "misc.typ": *
-#import "object.typ": problem, definition, theorem
-#import "solution.typ": if_solutions, if_no_solutions, solution
+#import "object.typ": problem, definition, theorem, example, remark, generic
+#import "solution.typ": (
+ if_solutions,
+ if_no_solutions,
+ if_solutions_else,
+ solution,
+ instructornote,
+)
/// Main handout wrapper.
diff --git a/lib/typst/local/handout/0.1.0/object.typ b/lib/typst/local/handout/0.1.0/object.typ
index 7d4d09b..ed38683 100644
--- a/lib/typst/local/handout/0.1.0/object.typ
+++ b/lib/typst/local/handout/0.1.0/object.typ
@@ -98,3 +98,11 @@
#let theorem = _mkobj("Theorem")
#let example = _mkobj("Example")
#let remark = _mkobj("Remark")
+
+#let generic(obj_content) = {
+ block(
+ above: 8mm,
+ below: 2mm,
+ text(weight: "bold", obj_content),
+ )
+}
diff --git a/lib/typst/local/handout/0.1.0/solution.typ b/lib/typst/local/handout/0.1.0/solution.typ
index abb54b2..2af06c2 100755
--- a/lib/typst/local/handout/0.1.0/solution.typ
+++ b/lib/typst/local/handout/0.1.0/solution.typ
@@ -1,4 +1,4 @@
-#import "misc.typ": ored
+#import "misc.typ": ored, oblue
/// If false, hide instructor info.
///
@@ -27,6 +27,10 @@
if not show_solutions { content }
}
+#let if_solutions_else(if_yes, if_no) = {
+ if show_solutions { if_yes } else { if_no }
+}
+
#let solution(content) = {
if_solutions(
align(
@@ -54,3 +58,31 @@
),
)
}
+
+#let instructornote(content) = {
+ if_solutions(
+ align(
+ center,
+ stack(
+ block(
+ width: 100%,
+ breakable: false,
+ fill: oblue,
+ stroke: oblue + 2pt,
+ inset: 1.5mm,
+ align(left, text(fill: white, weight: "bold", [Instructor note:])),
+ ),
+
+ block(
+ width: 100%,
+ height: auto,
+ breakable: false,
+ fill: oblue.lighten(80%).desaturate(10%),
+ stroke: oblue + 2pt,
+ inset: 3mm,
+ align(left, content),
+ ),
+ ),
+ ),
+ )
+}
diff --git a/src/Advanced/Fast Inverse Root/main.typ b/src/Advanced/Fast Inverse Root/main.typ
new file mode 100644
index 0000000..e36d184
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/main.typ
@@ -0,0 +1,31 @@
+#import "@local/handout:0.1.0": *
+
+// Bonus:
+// - Floats vs fixed point
+// - Float density
+// - Find non-floatable rational numbers
+// - What if we use `n`-bit floats?
+
+#show: doc => handout(
+ doc,
+ group: "Advanced 2",
+ title: [Fast Inverse Square Root],
+ by: "Mark",
+)
+
+#include "parts/00 intro.typ"
+#pagebreak()
+
+#include "parts/01 int.typ"
+#pagebreak()
+
+#include "parts/02 float.typ"
+#pagebreak()
+
+#include "parts/03 approx.typ"
+#pagebreak()
+
+#include "parts/04 quake.typ"
+#pagebreak()
+
+#include "parts/05 bonus.typ"
diff --git a/src/Advanced/Fast Inverse Root/meta.toml b/src/Advanced/Fast Inverse Root/meta.toml
new file mode 100644
index 0000000..5a1bdbd
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/meta.toml
@@ -0,0 +1,7 @@
+[metadata]
+title = "Fast Inverse Square Root"
+
+
+[publish]
+handout = true
+solutions = true
diff --git a/src/Advanced/Fast Inverse Root/parts/00 intro.typ b/src/Advanced/Fast Inverse Root/parts/00 intro.typ
new file mode 100644
index 0000000..d0ca1b5
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/parts/00 intro.typ
@@ -0,0 +1,45 @@
+#import "@local/handout:0.1.0": *
+
+= Introduction
+
+In 2005, ID Software published the source code of _Quake III Arena_, a popular game released in 1999. \
+This caused quite a stir: ID Software was responsible for many games popular among old-school engineers (most notably _Doom_, which has a place in programmer humor even today).
+
+#v(2mm)
+
+Naturally, this community immediately began dissecting _Quake_'s source. \
+One particularly interesting function is reproduced below, with original comments: \
+
+#v(3mm)
+
+```c
+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 ); // [redacted]
+ 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;
+}
+```
+
+#v(3mm)
+
+This code defines a function `Q_sqrt`, which was used as a fast approximation of the inverse square root in graphics routines. (in other words, `Q_sqrt` efficiently approximates $1 div sqrt(x)$)
+
+#v(3mm)
+
+The key word here is "fast": _Quake_ ran on very limited hardware, and traditional approximation techniques (like Taylor series)#footnote[Taylor series aren't used today, and for the same reason. There are better ways.] were too computationally expensive to be viable.
+
+#v(3mm)
+
+Our goal today is to understand how `Q_sqrt` works. \
+To do that, we'll first need to understand how computers represent numbers. \
+We'll start with simple binary integers---turn the page.
diff --git a/src/Advanced/Fast Inverse Root/parts/01 int.typ b/src/Advanced/Fast Inverse Root/parts/01 int.typ
new file mode 100644
index 0000000..0bc07bc
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/parts/01 int.typ
@@ -0,0 +1,102 @@
+#import "@local/handout:0.1.0": *
+
+= Integers
+
+#definition()
+A _bit string_ is a string of binary digits. \
+In this handout, we'll denote bit strings with the prefix `0b`. \
+#note[This prefix is only notation---it is _not_ part of the string itself.] \
+For example, $1001$ is the number "one thousand and one," while $#text([`0b1001`])$ is the string of bits "1 0 0 1".
+
+#v(2mm)
+We will separate long bit strings with underscores for readability. \
+Underscores have no meaning: $#text([`0b1111_0000`]) = #text([`0b11110000`])$.
+
+#problem()
+What is the value of the following bit strings, if we interpret them as integers in base 2?
+- `0b0001_1010`
+- `0b0110_0001`
+
+#solution([
+ - $#text([`0b0001_1010`]) = 2 + 8 + 16 = 26$
+ - $#text([`0b0110_0001`]) = 1 + 32 + 64 = 95$
+])
+
+#v(1fr)
+
+#definition()
+We can interpret a bit string in any number of ways. \
+One such interpretation is the _unsigned integer_, or `uint` for short. \
+`uint`s allow us to represent positive (hence "unsigned") integers using 32-bit strings.
+
+#v(2mm)
+
+The value of a `uint` is simply its value as a binary number:
+- $#text([`0b00000000_00000000_00000000_00000000`]) = 0$
+- $#text([`0b00000000_00000000_00000000_00000011`]) = 3$
+- $#text([`0b00000000_00000000_00000000_00100000`]) = 32$
+- $#text([`0b00000000_00000000_00000000_10000010`]) = 130$
+
+#problem()
+What is the largest number we can represent with a 32-bit `uint`?
+
+#solution([
+ $#text([`0b11111111_11111111_11111111_11111111`]) = 2^(32)-1$
+])
+
+#v(1fr)
+#pagebreak()
+
+#problem()
+Find the value of each of the following 32-bit unsigned integers:
+- `0b00000000_00000000_00000101_00111001`
+- `0b00000000_00000000_00000001_00101100`
+- `0b00000000_00000000_00000100_10110000`
+#hint([The third conversion is easy---look carefully at the second.])
+
+#instructornote[
+ Consider making a list of the powers of two $>= 1024$ on the board.
+]
+
+#solution([
+ - $#text([`0b00000000_00000000_00000101_00111001`]) = 1337$
+ - $#text([`0b00000000_00000000_00000001_00101100`]) = 300$
+ - $#text([`0b00000000_00000000_00000010_01011000`]) = 1200$
+ Notice that the third int is the second shifted left twice (i.e, multiplied by 4)
+])
+
+#v(1fr)
+
+
+#definition()
+In general, fast division of `uints` is difficult#footnote([One may use repeated subtraction, but this isn't efficient.]). \
+Division by powers of two, however, is incredibly easy: \
+To divide by two, all we need to do is shift the bits of our integer right.
+
+#v(2mm)
+
+For example, consider $#text[`0b0000_0110`] = 6$. \
+If we insert a zero at the left end of this string and delete the zero at the right \
+(thus "shifting" each bit right), we get `0b0000_0011`, which is 3. \
+
+#v(2mm)
+
+Of course, we lose the remainder when we right-shift an odd number: \
+$9$ shifted right is $4$, since `0b0000_1001` shifted right is `0b0000_0100`.
+
+#problem()
+Right shifts are denoted by the `>>` symbol: \
+$#text[`00110`] #text[`>>`] n$ means "shift `0b0110` right $n$ times." \
+Find the value of the following:
+- $12 #text[`>>`] 1$
+- $27 #text[`>>`] 3$
+- $16 #text[`>>`] 8$
+#note[Naturally, you'll have to convert these integers to binary first.]
+
+#solution[
+ - $12 #text[`>>`] 1 = 6$
+ - $27 #text[`>>`] 3 = 3$
+ - $16 #text[`>>`] 8 = 0$
+]
+
+#v(1fr)
diff --git a/src/Advanced/Fast Inverse Root/parts/02 float.typ b/src/Advanced/Fast Inverse Root/parts/02 float.typ
new file mode 100644
index 0000000..db056ff
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/parts/02 float.typ
@@ -0,0 +1,207 @@
+#import "@local/handout:0.1.0": *
+#import "@preview/cetz:0.3.1"
+
+= Floats
+#definition()
+_Binary decimals_#footnote([Note that "binary decimal" is a misnomer---"deci" means "ten"!]) are very similar to base-10 decimals.\
+In base 10, we interpret place value as follows:
+- $0.1 = 10^(-1)$
+- $0.03 = 3 times 10^(-2)$
+- $0.0208 = 2 times 10^(-2) + 8 times 10^(-4)$
+
+#v(5mm)
+
+We can do the same in base 2:
+- $#text([`0.1`]) = 2^(-1) = 0.5$
+- $#text([`0.011`]) = 2^(-2) + 2^(-3) = 0.375$
+- $#text([`101.01`]) = 5.125$
+
+#v(5mm)
+
+#problem()
+Rewrite the following binary decimals in base 10: \
+#note([You may leave your answer as a fraction.])
+- `1011.101`
+- `110.1101`
+
+
+#v(1fr)
+#pagebreak()
+
+#definition()
+Another way we can interpret a bit string is as a _signed floating-point decimal_, or a `float` for short. \
+Floats represent a subset of the real numbers, and are interpreted as follows: \
+#note([The following only applies to floats that consist of 32 bits. We won't encounter any others today.])
+
+#align(
+ center,
+ box(
+ inset: 2mm,
+ cetz.canvas({
+ import cetz.draw: *
+
+ let chars = (
+ `0`,
+ `b`,
+ `0`,
+ `_`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `_`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `_`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `_`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ `0`,
+ )
+
+ let x = 0
+ for c in chars {
+ content((x, 0), c)
+ x += 0.25
+ }
+
+ let y = -0.4
+ line((0.3, y), (0.65, y))
+ content((0.45, y - 0.2), [s])
+
+ line((0.85, y), (2.9, y))
+ content((1.9, y - 0.2), [exponent])
+
+ line((3.10, y), (9.4, y))
+ content((6.3, y - 0.2), [fraction])
+ }),
+ ),
+)
+
+- The first bit denotes the sign of the float's value
+ We'll label it $s$. \
+ If $s = #text([`1`])$, this float is negative; if $s = #text([`0`])$, it is positive.
+
+- The next eight bits represent the _exponent_ of this float.
+ #note([(we'll see what that means soon)]) \
+ We'll call the value of this eight-bit binary integer $E$. \
+ Naturally, $0 <= E <= 255$ #note([(since $E$ consist of eight bits)])
+
+- The remaining 23 bits represent the _fraction_ of this float. \
+ They are interpreted as the fractional part of a binary decimal. \
+ For example, the bits `0b10100000_00000000_00000000` represent $0.5 + 0.125 = 0.625$. \
+ We'll call the value of these bits as a binary integer $F$. \
+ Their value as a binary decimal is then $F div 2^23$. #note([(convince yourself of this)])
+
+
+#problem(label: "floata")
+Consider `0b01000001_10101000_00000000_00000000`. \
+Find the $s$, $E$, and $F$ we get if we interpret this bit string as a `float`. \
+#note([Leave $F$ as a sum of powers of two.])
+
+#solution([
+ $s = 0$ \
+ $E = 258$ \
+ $F = 2^31+2^19 = 2,621,440$
+])
+
+#v(1fr)
+
+
+#definition(label: "floatdef")
+The final value of a float with sign $s$, exponent $E$, and fraction $F$ is
+
+$
+ (-1)^s times 2^(E - 127) times (1 + F / (2^(23)))
+$
+
+Notice that this is very similar to base-10 scientific notation, which is written as
+
+$
+ (-1)^s times 10^(e) times (f)
+$
+
+#note[
+ We subtract 127 from $E$ so we can represent positive and negative numbers. \
+ $E$ is an eight bit binary integer, so $0 <= E <= 255$ and thus $-127 <= (E - 127) <= 127$.
+]
+
+#problem()
+Consider `0b01000001_10101000_00000000_00000000`. \
+This is the same bit string we used in @floata. \
+
+#v(2mm)
+
+What value do we get if we interpret this bit string as a float? \
+#hint([$21 div 16 = 1.3125$])
+
+#solution([
+ This is 21:
+ $
+ 2^(131) times (1 + (2^(21) + 2^(19)) / (2^(23)))
+ = 2^(4) times (1 + 0.25 + 0.0625)
+ = 16 times (1.3125)
+ = 21
+ $
+])
+
+#v(1fr)
+#pagebreak()
+
+#problem()
+Encode $12.5$ as a float. \
+#hint([$12.5 div 8 = 1.5625$])
+
+#solution([
+ $
+ 12.5
+ = 8 times 1.5625
+ = 2^(3) times (1 + (0.5 + 0.0625))
+ = 2^(130) times (1 + (2^(22) + 2^(19)) / (2^(23)))
+ $
+
+ which is `0b01000001_01001000_00000000_00000000`. \
+])
+
+
+#v(1fr)
+
+#definition()
+Say we have a bit string $x$. \
+We'll let $x_f$ denote the value we get if we interpret $x$ as a float, \
+and we'll let $x_i$ denote the value we get if we interpret $x$ an integer.
+
+#problem()
+Let $x = #text[`0b01000001_01001000_00000000_00000000`]$. \
+What are $x_f$ and $x_i$? #note([As always, you may leave big numbers as powers of two.])
+#solution([
+ $x_f = 12.5$
+
+ #v(2mm)
+
+ $x_i = 2^30 + 2^24 + 2^22 + 2^19 = 11,095,237,632$
+])
+
+#v(1fr)
diff --git a/src/Advanced/Fast Inverse Root/parts/03 approx.typ b/src/Advanced/Fast Inverse Root/parts/03 approx.typ
new file mode 100644
index 0000000..5934628
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/parts/03 approx.typ
@@ -0,0 +1,173 @@
+#import "@local/handout:0.1.0": *
+#import "@preview/cetz:0.3.1"
+#import "@preview/cetz-plot:0.1.0": plot, chart
+
+= Integers and Floats
+
+#generic("Observation:")
+If $x$ is smaller than 1, $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_2(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_2(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)_2 - (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
+$
+#note([
+ In other words, we're finding an expression for $x$ as a float
+ in terms of $x$ as an int.
+])
+
+#solution([
+ Let $E$ and $F$ be the exponent and float bits of $x_f$. \
+ We then have:
+ $
+ log_2(x_f)
+ &= log_2 ( 2^(E-127) times (1 + (F) / (2^23)) ) \
+ &= E - 127 + log_2(1 + F / (2^23)) \
+ & approx E-127 + F / (2^23) + epsilon \
+ &= 1 / (2^23)(2^23 E + F) - 127 + epsilon \
+ &= 1 / (2^23)(x_i) - 127 + epsilon
+ $
+])
+
+#v(1fr)
+
+
+#problem()
+Using basic log rules, rewrite $log_2(1 / sqrt(x))$ in terms of $log_2(x)$.
+
+#solution([
+ $
+ log_2(1 / sqrt(x)) = (-1) / (2)log_2(x)
+ $
+])
+
+#v(1fr)
diff --git a/src/Advanced/Fast Inverse Root/parts/04 quake.typ b/src/Advanced/Fast Inverse Root/parts/04 quake.typ
new file mode 100644
index 0000000..5e2d57f
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/parts/04 quake.typ
@@ -0,0 +1,210 @@
+#import "@local/handout:0.1.0": *
+
+= The Fast Inverse Square Root
+
+A simplified version of the _Quake_ routine we are studying is reproduced below.
+
+#v(2mm)
+
+```c
+float Q_rsqrt( float number ) {
+ long i = * ( long * ) &number;
+ i = 0x5f3759df - ( i >> 1 );
+ return * ( float * ) &i;
+}
+```
+
+#v(2mm)
+
+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:
+$
+ #text[`Q_sqrt`] (n_f) =
+ 6240089 - (n_i div 2)
+ #h(10mm)
+ approx 1 / sqrt(n_f)
+$
+
+#note[
+ `0x5f3759df` is $6240089$ in hexadecimal. \
+ Ask an instructor to explain if you don't know what this means. \
+ It is a magic number hard-coded into `Q_sqrt`.
+]
+
+#v(2mm)
+
+Our goal in this section is to understand why this works:
+- How does Quake approximate $1 / sqrt(x)$ by simply subtracting and dividing by two?
+- What's special about $6240089$?
+
+
+
+#v(1fr)
+
+#remark()
+For those that are interested, here are the details of the "code-to-math" translation:
+
+- "`long i = * (long *) &number`" is C magic that tells the compiler \
+ to set `i` to the `uint` value of the bits of `number`. \
+ #note[
+ "long" refers to a "long integer", which has 32 bits. \
+ Normal `int`s have 16 bits, `short int`s have 8.
+ ] \
+ In other words, `number` is $n_f$ and `i` is $n_i$.
+#v(2mm)
+
+
+- Notice the right-shift in the second line of the function. \
+ We translated `(i >> 1)` into $(n_i div 2)$.
+#v(2mm)
+
+- "`return * (float *) &i`" is again C magic. \
+ Much like before, it tells us to return the value of the bits of `i` as a float.
+#pagebreak()
+
+#generic("Setup:")
+We are now ready to show that $#text[`Q_sqrt`] (x)$ effectively approximates $1/sqrt(x)$. \
+For convenience, let's call the bit string of the inverse square root $r$. \
+In other words,
+$
+ r_f := 1 / (sqrt(n_f))
+$
+This is the value we want to approximate. \
+
+#problem(label: "finala")
+Find an approximation for $log_2(r_f)$ in terms of $n_i$ and $epsilon$ \
+#note[Remember, $epsilon$ is the correction constant in our approximation of $log_2(1 + x)$.]
+
+#solution[
+ $
+ log_2(r_f)
+ = log_2(1 / sqrt(n_f))
+ = (-1) / 2 log_2(n_f)
+ approx (-1) / 2 ( (n_i) / (2^23) + epsilon - 127 )
+ $
+]
+
+#v(1fr)
+
+#problem(label: "finalb")
+Let's call the "magic number" in the code above $kappa$, so that
+$
+ #text[`Q_sqrt`] (n_f) = kappa - (n_i div 2)
+$
+Use @convert and @finala to show that $#text[`Q_sqrt`] (n_f) approx r_i$ \
+#note(type: "Note")[
+ If we know $r_i$, we know $r_f$. \
+ We don't even need to convert between the two---the underlying bits are the same!
+]
+
+#solution[
+ From @convert, we know that
+ $
+ log_2(r_f) approx (r_i) / (2^23) + epsilon - 127
+ $
+
+ Combining this with the result from @finala, we get:
+ $
+ (r_i) / (2^23) + epsilon - 127
+ &approx (-1) / (2) ( (n_i) / (2^23) + epsilon - 127) \
+ (r_i) / (2^23)
+ &approx (-1) / (2) ( (n_i) / (2^23)) + 3 / 2 (127 - epsilon) \
+ r_i
+ &approx (-1) / 2 (n_i) + 2^23 3 / 2(127 - epsilon)
+ = 2^23 3 / 2 (127 - epsilon) - (n_i) / 2
+ $
+
+ #v(2mm)
+
+ This is exactly what we need! If we set $kappa$ to $(3 times 2^22) (127-epsilon)$, then
+ $
+ r_i approx kappa - (n_i div 2) = #text[`Q_sqrt`] (n_f)
+ $
+]
+
+#v(1fr)
+
+#problem(label: "finalc")
+What is the exact value of $kappa$ in terms of $epsilon$? \
+#hint[Look at @finalb. We already found it!]
+
+#solution[
+ This problem makes sure our students see that
+ $kappa = (3 times 2^22) (127 - epsilon)$. \
+ See the solution to @finalb.
+]
+
+#v(2cm)
+
+#pagebreak()
+
+#remark()
+In @finalc we saw that $kappa = (3 times 2^22) (127 - epsilon)$. \
+Looking at the code again, we see that $kappa = #text[`0x5f3759df`]$ in _Quake_:
+
+#v(2mm)
+
+```c
+float Q_rsqrt( float number ) {
+ long i = * ( long * ) &number;
+ i = 0x5f3759df - ( i >> 1 );
+ return * ( float * ) &i;
+}
+```
+
+#v(2mm)
+Using a calculator and some basic algebra, we can find the $epsilon$ this code uses: \
+#note[Remember, #text[`0x5f3759df`] is $6240089$ in hexadecimal.]
+$
+ (3 times 2^22) (127 - epsilon) &= 6240089 \
+ (127 - epsilon) &= 126.955 \
+ epsilon &= 0.0450466
+$
+
+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$.
+
+#remark()
+And now, we're done! \
+We've shown that `Q_sqrt(x)` approximates $1/sqrt(x)$ fairly well. \
+
+#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 (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)
+ $
+]
diff --git a/src/Advanced/Fast Inverse Root/parts/05 bonus.typ b/src/Advanced/Fast Inverse Root/parts/05 bonus.typ
new file mode 100644
index 0000000..3cf5177
--- /dev/null
+++ b/src/Advanced/Fast Inverse Root/parts/05 bonus.typ
@@ -0,0 +1,36 @@
+#import "@local/handout:0.1.0": *
+
+= Bonus -- More about Floats
+
+#problem()
+Convince yourself that all numbers that can be represented as a float are rational.
+
+#problem()
+Find a rational number that cannot be represented as a float.
+
+#v(1fr)
+
+#problem()
+What is the smallest positive 32-bit float?
+
+#v(1fr)
+
+#problem()
+What is the largest positive 32-bit float?
+
+#v(1fr)
+
+#problem()
+How many floats are between $-1$ and $1$?
+
+#v(1fr)
+
+#problem()
+How many floats are between $1$ and $2$?
+
+#v(1fr)
+
+#problem()
+How many floats are between $1$ and $128$?
+
+#v(1fr)
diff --git a/src/Advanced/Introduction to Quantum/src/main.tex b/src/Advanced/Introduction to Quantum/src/main.tex
index 4708319..d8ddfab 100755
--- a/src/Advanced/Introduction to Quantum/src/main.tex
+++ b/src/Advanced/Introduction to Quantum/src/main.tex
@@ -1,18 +1,3 @@
-% Copyright (C) 2023
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% (at your option) any later version.
-%
-% You may have received a copy of the GNU General Public License
-% along with this program. If not, see .
-%
-%
-%
-% If you edit this, please give credit!
-% Quality handouts take time to make.
-
% use the [nosolutions] flag to hide solutions,
% use the [solutions] flag to show solutions.
\documentclass[
diff --git a/src/Advanced/Nonstandard Analysis/main.tex b/src/Advanced/Nonstandard Analysis/main.tex
index c0cc0e9..4daa657 100755
--- a/src/Advanced/Nonstandard Analysis/main.tex
+++ b/src/Advanced/Nonstandard Analysis/main.tex
@@ -1,19 +1,3 @@
-% Copyright (C) 2023
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% (at your option) any later version.
-%
-% You may have received a copy of the GNU General Public License
-% along with this program. If not, see .
-%
-%
-%
-% If you edit this, please give credit!
-% Quality handouts take time to make.
-
-
% use [nosolutions] flag to hide solutions.
% use [solutions] flag to show solutions.
\documentclass[
diff --git a/src/Advanced/Nonstandard Analysis/parts/dual.tex b/src/Advanced/Nonstandard Analysis/parts/dual.tex
index b7eb55a..344447d 100644
--- a/src/Advanced/Nonstandard Analysis/parts/dual.tex
+++ b/src/Advanced/Nonstandard Analysis/parts/dual.tex
@@ -1,19 +1,3 @@
-% Copyright (C) 2023
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% (at your option) any later version.
-%
-% You may have received a copy of the GNU General Public License
-% along with this program. If not, see .
-%
-%
-%
-% If you edit this, please give credit!
-% Quality handouts take time to make.
-
-
\section{Dual Numbers}
\definition{}
diff --git a/src/Advanced/Nonstandard Analysis/parts/extensions.tex b/src/Advanced/Nonstandard Analysis/parts/extensions.tex
index e0cb5d7..96165a3 100644
--- a/src/Advanced/Nonstandard Analysis/parts/extensions.tex
+++ b/src/Advanced/Nonstandard Analysis/parts/extensions.tex
@@ -1,18 +1,3 @@
-% Copyright (C) 2023
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% (at your option) any later version.
-%
-% You may have received a copy of the GNU General Public License
-% along with this program. If not, see .
-%
-%
-%
-% If you edit this, please give credit!
-% Quality handouts take time to make.
-
\section{Extensions of $\mathbb{R}$}
\definition{}
diff --git a/src/Advanced/Nonstandard Analysis/parts/supremum.tex b/src/Advanced/Nonstandard Analysis/parts/supremum.tex
index bd0dbf7..d4fb16f 100644
--- a/src/Advanced/Nonstandard Analysis/parts/supremum.tex
+++ b/src/Advanced/Nonstandard Analysis/parts/supremum.tex
@@ -1,19 +1,3 @@
-% Copyright (C) 2023
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% (at your option) any later version.
-%
-% You may have received a copy of the GNU General Public License
-% along with this program. If not, see .
-%
-%
-%
-% If you edit this, please give credit!
-% Quality handouts take time to make.
-
-
\section*{The supremum \& the infimum}
\definition{}
diff --git a/src/Warm-Ups/Slide Rules/main.tex b/src/Warm-Ups/Slide Rules/main.tex
new file mode 100755
index 0000000..f2f5471
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/main.tex
@@ -0,0 +1,78 @@
+% use [nosolutions] flag to hide solutions.
+% use [solutions] flag to show solutions.
+\documentclass[
+ solutions,
+ shortwarning
+]{../../../lib/tex/ormc_handout}
+\usepackage{../../../lib/tex/macros}
+
+
+\usepackage{pdfpages}
+\usepackage{sliderule}
+\usepackage{changepage}
+
+% Args:
+% x, top scale y, label
+\newcommand{\slideruleind}[3]{
+ \draw[
+ line width=1mm,
+ draw=black,
+ opacity=0.3,
+ text opacity=1
+ ]
+ ({#1}, {#2 + 1})
+ --
+ ({#1}, {#2 - 1.1})
+ node [below] {#3};
+}
+
+
+\uptitlel{Advanced}
+\uptitler{\smallurl{}}
+\title{Warm-Up: Slide Rules}
+\subtitle{Prepared by Mark on \today}
+
+\begin{document}
+
+ \maketitle
+
+
+ \begin{center}
+ \begin{minipage}{6cm}
+ Dad says that anyone who can't use
+ a slide rule is a cultural illiterate
+ and should not be allowed to vote.
+
+ \vspace{1ex}
+
+ \textit{Have Space Suit --- Will Travel, 1958}
+ \end{minipage}
+ \end{center}
+ \hfill
+
+ \input{parts/0 logarithms.tex}
+ \input{parts/1 intro.tex}
+ \input{parts/2 multiplication.tex}
+
+ % Make sure the slide rule is on an odd page,
+ % so that double-sided printing won't require
+ % students to tear off problems.
+ \checkoddpage
+ \ifoddpage\else
+ \vspace*{\fill}
+ \begin{center}
+ {
+ \Large
+ \textbf{This page unintentionally left blank.}
+ }
+ \end{center}
+ \vspace{\fill}
+ \pagebreak
+ \fi
+
+ \includepdf[
+ pages=1,
+ fitpaper=true
+ ]{resources/rule.pdf}
+
+\end{document}
\ No newline at end of file
diff --git a/src/Warm-Ups/Slide Rules/meta.toml b/src/Warm-Ups/Slide Rules/meta.toml
new file mode 100644
index 0000000..59669b6
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/meta.toml
@@ -0,0 +1,6 @@
+[metadata]
+title = "Slide Rules"
+
+[publish]
+handout = false
+solutions = true
diff --git a/src/Warm-Ups/Slide Rules/parts/0 logarithms.tex b/src/Warm-Ups/Slide Rules/parts/0 logarithms.tex
new file mode 100644
index 0000000..172fade
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/parts/0 logarithms.tex
@@ -0,0 +1,63 @@
+\section{Logarithms}
+
+\definition{}
+The \textit{logarithm} is the inverse of the exponent. That is, if $b^p = c$, then $\log_b{c} = p$. \\
+In other words, $\log_b{c}$ asks the question ``what power do I need to raise $b$ to to get $c$?'' \\
+
+\problem{}
+Evaluate the following by hand:
+
+\begin{enumerate}
+ \item $\log_{10}{(1000)}$
+ \vfill
+ \item $\log_2{(64)}$
+ \vfill
+ \item $\log_2{(\frac{1}{4})}$
+ \vfill
+ \item $\log_x{(x)}$ for any $x$
+ \vfill
+ \item $log_x{(1)}$ for any $x$
+ \vfill
+\end{enumerate}
+
+\problem{}
+Prove the following:
+
+\begin{enumerate}[itemsep=2mm]
+ \item $\log_b{(b^x)} = x$
+ \vfill
+ \item $b^{\log_b{x}} = x$
+ \vfill
+ \item $\log_b{(xy)} = \log_b{(x)} + \log_b{(y)}$
+ \vfill
+ \item $\log_b{(\frac{x}{y})} = \log_b{(x)} - \log_b{(y)}$
+ \vfill
+ \item $\log_b{(x^y)} = y \log_b{(x)}$
+ \vfill
+\end{enumerate}
+
+
+\begin{instructornote}
+ A good intro to the following sections is the linear slide rule:
+ \note{(note that these rules start at 0)}
+ \begin{center}
+ \begin{tikzpicture}[scale=0.5]
+ \linearscale{2}{1}{}
+ \linearscale{0}{0}{}
+
+ \slideruleind
+ {5}
+ {1}
+ {2 + 3 = 5}
+ \end{tikzpicture}
+ \end{center}
+
+ Take two linear rules, offset one, and you add.
+ Do the same with a log scale, and you multiply! \\
+
+ \linehack{}
+
+ After assembling the paper slide rule, you can make a visor with some transparent tape.
+\end{instructornote}
+
+\pagebreak
\ No newline at end of file
diff --git a/src/Warm-Ups/Slide Rules/parts/1 intro.tex b/src/Warm-Ups/Slide Rules/parts/1 intro.tex
new file mode 100644
index 0000000..8d839c8
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/parts/1 intro.tex
@@ -0,0 +1,43 @@
+\section{Introduction}
+
+Mathematicians, physicists, and engineers needed to quickly compute products long before computers conquered the world.
+
+\medskip
+
+The \textit{slide rule} is an instrument that uses the logarithm to solve this problem. Before you continue, cut out and assemble your slide rule.
+
+\medskip
+
+There are four scales on your slide rule, each labeled with a letter on the left side:
+
+\def\sliderulewidth{13}
+\begin{center}
+\begin{tikzpicture}[scale=1]
+ \tscale{0}{9}{T}
+ \kscale{0}{8}{K}
+ \abscale{0}{7}{A}
+
+ \abscale{0}{5.5}{B}
+ \ciscale{0}{4.5}{CI}
+ \cdscale{0}{3.5}{C}
+
+ \cdscale{0}{2}{D}
+ \lscale{0}{1}{L}
+ \sscale{0}{0}{S}
+\end{tikzpicture}
+\end{center}
+
+Each scale's ``generating function'' is on the right:
+\begin{itemize}
+ \item T: $\tan$
+ \item K: $x^3$
+ \item A,B: $x^2$
+ \item CI: $\frac{1}{x}$
+ \item C, D: $x$
+ \item L: $\log_{10}(x)$
+ \item S: $\sin$
+\end{itemize}
+
+Once you understand the layout of your slide rule, move on to the next page.
+
+\pagebreak
diff --git a/src/Warm-Ups/Slide Rules/parts/2 multiplication.tex b/src/Warm-Ups/Slide Rules/parts/2 multiplication.tex
new file mode 100644
index 0000000..fee1493
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/parts/2 multiplication.tex
@@ -0,0 +1,299 @@
+\section{Multiplication}
+
+We'll use the C and D scales of your slide rule to multiply. \\
+
+Say we want to multiply $2 \times 3$. First, move the \textit{left-hand index} of the C scale over the smaller number, $2$:
+
+\def\sliderulewidth{10}
+\begin{center}
+\begin{tikzpicture}[scale=1]
+ \cdscale{\cdscalefn(2)}{1}{C}
+ \cdscale{0}{0}{D}
+\end{tikzpicture}
+\end{center}
+
+Then we'll find the second number, $3$ on the C scale, and read the D scale under it:
+
+\begin{center}
+\begin{tikzpicture}[scale=1]
+ \cdscale{\cdscalefn(2)}{1}{C}
+ \cdscale{0}{0}{D}
+
+ \slideruleind
+ {\cdscalefn(6)}
+ {1}
+ {6}
+
+\end{tikzpicture}
+\end{center}
+
+Of course, our answer is 6.
+
+\problem{}
+What is $1.15 \times 2.1$? \\
+Use your slide rule.
+
+\begin{solution}
+ \begin{center}
+ \begin{tikzpicture}[scale=1]
+ \cdscale{\cdscalefn(1.15)}{1}{C}
+ \cdscale{0}{0}{D}
+
+ \slideruleind
+ {\cdscalefn(1.15)}
+ {1}
+ {1.15}
+
+ \slideruleind
+ {\cdscalefn(1.15) + \cdscalefn(2.1)}
+ {1}
+ {2.415}
+
+ \end{tikzpicture}
+ \end{center}
+\end{solution}
+
+\vfill
+
+Note that your answer isn't exact. $1.15 \times 2.1 = 2.415$, but an answer accurate within two decimal places is close enough for most practical applications. \\
+
+\pagebreak
+
+Look at your C and D scales again. They contain every number between 1 and 10, but no more than that.
+What should we do if we want to calculate $32 \times 210$? \\
+
+\problem{}
+Using your slide rule, calculate $32 \times 210$. \\
+%\hint{$32 = 3.2 \times 10^1$}
+
+\begin{solution}
+ \begin{center}
+ \begin{tikzpicture}[scale=1]
+ \cdscale{\cdscalefn(2.1)}{1}{C}
+ \cdscale{0}{0}{D}
+
+ \slideruleind
+ {\cdscalefn(2.1)}
+ {1}
+ {2.1}
+
+ \slideruleind
+ {\cdscalefn(2.1) + \cdscalefn(3.2)}
+ {1}
+ {6.72}
+
+ \end{tikzpicture}
+ \end{center}
+
+ Placing the decimal point correctly is your job. \\
+ $10^1 \times 10^2 = 10^3$, so our final answer is $6.72 \times 10^3 = 672$.
+\end{solution}
+
+\vfill
+
+%This method of writing numbers is called \textit{scientific notation}. In the form $a \times 10^b$, $a$ is called the \textit{mantissa}, and $b$, the \textit{exponent}. \\
+
+%You may also see expressions like $4.3\text{e}2$. This is equivalent to $4.3 \times 10^2$, but is more compact.
+
+
+\problem{}
+Compute the following:
+\begin{enumerate}
+ \item $1.44 \times 52$
+ \item $0.38 \times 1.24$
+ \item $\pi \times 2.35$
+\end{enumerate}
+
+\begin{solution}
+ \begin{enumerate}
+ \item $1.44 \times 52 = 74.88$
+ \item $0.38 \times 1.24 = 0.4712$
+ \item $\pi \times 2.35 = 7.382$
+ \end{enumerate}
+\end{solution}
+
+\vfill
+\pagebreak
+
+\problem{}
+Note that the numbers on your C and D scales are logarithmically spaced.
+
+\def\sliderulewidth{13}
+\begin{center}
+\begin{tikzpicture}[scale=1]
+ \cdscale{0}{1}{C}
+ \cdscale{0}{0}{D}
+\end{tikzpicture}
+\end{center}
+
+Why does our multiplication procedure work? \\
+%\hint{See \ref{logids}}
+
+\vfill
+\pagebreak
+
+Now we want to compute $7.2 \times 5.5$:
+
+\def\sliderulewidth{10}
+\begin{center}
+\begin{tikzpicture}[scale=0.8]
+ \cdscale{\cdscalefn(5.5)}{1}{C}
+ \cdscale{0}{0}{D}
+
+ \slideruleind
+ {\cdscalefn(5.5)}
+ {1}
+ {5.5}
+
+ \slideruleind
+ {\cdscalefn(5.5) + \cdscalefn(7.2)}
+ {1}
+ {???}
+
+\end{tikzpicture}
+\end{center}
+
+No matter what order we go in, the answer ends up off the scale. There must be another way. \\
+
+\medskip
+
+Look at the far right of your C scale. There's an arrow pointing to the $10$ tick, labeled \textit{right-hand index}. Move it over the \textit{larger} number, $7.2$:
+
+\begin{center}
+\begin{tikzpicture}[scale=1]
+ \cdscale{\cdscalefn(7.2) - \cdscalefn(10)}{1}{C}
+ \cdscale{0}{0}{D}
+
+ \slideruleind
+ {\cdscalefn(7.2)}
+ {1}
+ {7.2}
+
+\end{tikzpicture}
+\end{center}
+
+Now find the smaller number, $5.5$, on the C scale, and read the D scale under it:
+
+\begin{center}
+\begin{tikzpicture}[scale=1]
+ \cdscale{\cdscalefn(7.2) - \cdscalefn(10)}{1}{C}
+ \cdscale{0}{0}{D}
+
+
+ \slideruleind
+ {\cdscalefn(7.2)}
+ {1}
+ {7.2}
+
+ \slideruleind
+ {\cdscalefn(3.96)}
+ {1}
+ {3.96}
+
+\end{tikzpicture}
+\end{center}
+
+Our answer should be about $7 \times 5 = 35$, so let's move the decimal point: $5.5 \times 7.2 = 39.6$. We can do this by hand to verify our answer. \\
+
+\medskip
+
+\problem{}
+Why does this work? \par
+\hint{Add a second $D$ scale.}
+
+\begin{solution}
+ Consider the following picture, where I've put two D scales next to each other:
+
+ \begin{center}
+ \begin{tikzpicture}[scale=0.7]
+ \cdscale{\cdscalefn(7.2) - \cdscalefn(10)}{1}{C}
+ \cdscale{0}{0}{}
+ \cdscale{-10}{0}{}
+
+ \draw[
+ draw=black,
+ ]
+ (0, 0)
+ --
+ (0, -0.3)
+ node [below] {D};
+
+ \draw[
+ draw=black,
+ ]
+ (-10, 0)
+ --
+ (-10, -0.3)
+ node [below] {D};
+
+ \slideruleind
+ {-10 + \cdscalefn(7.2)}
+ {1}
+ {7.2}
+
+ \slideruleind
+ {\cdscalefn(7.2)}
+ {1}
+ {7.2}
+
+ \slideruleind
+ {\cdscalefn(3.96)}
+ {1}
+ {3.96}
+
+ \end{tikzpicture}
+ \end{center}
+
+ \medskip
+
+ The second D scale has been moved to the right by $(\log{10})$, so every value on it is $(\log{10})$ smaller than it should be.
+
+ \medskip
+
+ \medskip
+ In other words, the answer we get from reverse multiplication is the following: $\log{a} + \log{b} - \log{10}$. \\
+ This reduces to $\log{(\frac{a \times b}{10})}$, which explains the misplaced decimal point in $7.2 \times 5.5$.
+\end{solution}
+
+\vfill
+\pagebreak
+
+\problem{}
+Compute the following using your slide rule:
+\begin{enumerate}
+ \item $9 \times 8$
+ \item $15 \times 35$
+ \item $42.1 \times 7.65$
+ \item $6.5^2$
+\end{enumerate}
+
+\begin{solution}
+ \begin{enumerate}
+ \item $9 \times 8 = 72$
+ \item $15 \times 35 = 525$
+ \item $42.1 \times 7.65 = 322.065$
+ \item $6.5^2 = 42.25$
+ \end{enumerate}
+\end{solution}
+
+\vfill
+
+\problem{}
+Compute the following using your slide rule. \\
+
+\begin{enumerate}
+ \item $135 \div 15$
+ \item $68.2 \div 0.575$
+ \item $(118 \times 0.51) \div 6.6$
+\end{enumerate}
+
+\begin{solution}
+ \begin{enumerate}
+ \item $135 \div 15 = 9$
+ \item $68.2 \div 0.575 = 118.609$
+ \item $(118 \times 0.51) \div 6.6 = 9.118$
+ \end{enumerate}
+\end{solution}
+
+\vfill
+\pagebreak
\ No newline at end of file
diff --git a/src/Warm-Ups/Slide Rules/resources/rule.pdf b/src/Warm-Ups/Slide Rules/resources/rule.pdf
new file mode 100755
index 0000000..b8fc33b
Binary files /dev/null and b/src/Warm-Ups/Slide Rules/resources/rule.pdf differ
diff --git a/src/Warm-Ups/Slide Rules/resources/rule.svg b/src/Warm-Ups/Slide Rules/resources/rule.svg
new file mode 100755
index 0000000..9506a6d
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/resources/rule.svg
@@ -0,0 +1,24144 @@
+
+
diff --git a/src/Warm-Ups/Slide Rules/sliderule.sty b/src/Warm-Ups/Slide Rules/sliderule.sty
new file mode 100755
index 0000000..13e3995
--- /dev/null
+++ b/src/Warm-Ups/Slide Rules/sliderule.sty
@@ -0,0 +1,534 @@
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{sliderule}[2022/08/22 Slide rule tools]
+
+\RequirePackage{tikz}
+\RequirePackage{ifthen}
+
+
+% Scale functions:
+% See https://sliderulemuseum.com/SR_Scales.htm
+%
+% l: length of the rule
+% n: the number on the rule
+%
+% A/B: (l/2) * log(n)
+% C/D: l / log(n)
+% CI: abs(l * log(10 / n) - l)
+% K: (l/3) * log(n)
+%
+% L: n * l
+% T: l * log(10 * tan(n))
+% S: l * log(10 * sin(n))
+
+\def\sliderulewidth{10}
+
+\def\abscalefn(#1){(\sliderulewidth/2) * log10(#1)}
+\def\cdscalefn(#1){(\sliderulewidth * log10(#1))}
+\def\ciscalefn(#1){(\sliderulewidth - \cdscalefn(#1))}
+\def\kscalefn(#1){(\sliderulewidth/3) * log10(#1)}
+\def\lscalefn(#1){(\sliderulewidth * #1)}
+\def\tscalefn(#1){(\sliderulewidth * log10(10 * tan(#1)))}
+\def\sscalefn(#1){(\sliderulewidth * log10(10 * sin(#1)))}
+
+
+% Arguments:
+% Label
+% x of start
+% y of start
+\newcommand{\linearscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks
+ \foreach \i in {0,..., 10}{
+ \draw[black]
+ ({#1 + (\sliderulewidth / 10) * \i}, #2) --
+ ({#1 + (\sliderulewidth / 10) * \i}, #2 + 0.3)
+ node[above] {\i};
+ }
+
+ % Submarks
+ \foreach \n in {0, ..., 9} {
+ \foreach \i in {1,..., 9} {
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + (\sliderulewidth / 10) * (\n + \i / 10)}, #2) --
+ ({#1 + (\sliderulewidth / 10) * (\n + \i / 10)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + (\sliderulewidth / 10) * (\n + \i / 10)}, #2) --
+ ({#1 + (\sliderulewidth / 10) * (\n + \i / 10)}, #2 + 0.1);
+ }
+ }
+ }
+}
+
+
+% Arguments:
+% Label
+% x of start
+% y of start
+\newcommand{\abscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks 1 - 9
+ \foreach \i in {1,..., 9}{
+ \draw[black]
+ ({#1 + \abscalefn(\i)}, #2) --
+ ({#1 + \abscalefn(\i)}, #2 + 0.3)
+ node[above] {\i};
+ }
+ % Numbers and marks 10 - 100
+ \foreach \i in {1,..., 10}{
+ \draw[black]
+ ({#1 + \abscalefn(10 * \i)}, #2) --
+ ({#1 + \abscalefn(10 * \i)}, #2 + 0.3)
+ node[above] {\ifthenelse{\i=10}{1}{\i}};
+ }
+
+ % Submarks 1 - 9
+ \foreach \n in {1, ..., 9} {
+ \ifthenelse{\n<5}{
+ \foreach \i in {1,..., 9}
+ } {
+ \foreach \i in {2,4,6,8}
+ }
+ {
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + \abscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \abscalefn(\n + \i / 10)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \abscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \abscalefn(\n + \i / 10)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 10 - 100
+ \foreach \n in {10,20,...,90} {
+ \ifthenelse{\n<50}{
+ \foreach \i in {1,..., 9}
+ } {
+ \foreach \i in {2,4,6,8}
+ }
+ {
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + \abscalefn(\n + \i)}, #2) --
+ ({#1 + \abscalefn(\n + \i)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \abscalefn(\n + \i)}, #2) --
+ ({#1 + \abscalefn(\n + \i)}, #2 + 0.1);
+ }
+ }
+ }
+}
+
+\newcommand{\cdscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks 1 - 10
+ \foreach \i in {1,..., 10}{
+ \draw[black]
+ ({#1 + \cdscalefn(\i)}, #2) --
+ ({#1 + \cdscalefn(\i)}, #2 + 0.3)
+ node[above] {\ifthenelse{\i=10}{1}{\i}};
+ }
+
+ % Submarks 1 - 9
+ \foreach \n in {1, ..., 9} {
+ \ifthenelse{\n<3}{
+ \foreach \i in {5,10,...,95}
+ } {
+ \foreach \i in {10,20,...,90}
+ }
+ {
+ \ifthenelse{\i=50}{
+ \draw[black]
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2) --
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2 + 0.2);
+ \ifthenelse{\n=1}{
+ \draw
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2 + 0.2)
+ node [above] {1.5};
+ }{}
+ } {
+ \ifthenelse{
+ \i=10 \OR \i=20 \OR \i=30 \OR \i=40 \OR
+ \i=60 \OR \i=70 \OR \i=80 \OR \i=90
+ }{
+ \draw[black]
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2) --
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2 + 0.15);
+ } {
+ \draw[black]
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2) --
+ ({#1 + \cdscalefn(\n + \i / 100)}, #2 + 0.1);
+ }
+ }
+ }
+ }
+}
+
+\newcommand{\ciscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks
+ \foreach \i in {1,...,10}{
+ \draw[black]
+ ({#1 + \ciscalefn(\i)}, #2) --
+ ({#1 + \ciscalefn(\i)}, #2 + 0.3)
+ node[above] {\ifthenelse{\i=10}{1}{\ifthenelse{\i=0}{0}{.\i}}};
+ }
+
+ % Submarks 1 - 9
+ \foreach \n in {1, ..., 9} {
+ \ifthenelse{\n<3}{
+ \foreach \i in {5,10,...,95}
+ } {
+ \foreach \i in {10,20,...,90}
+ }
+ {
+ \ifthenelse{\i=50}{
+ \draw[black]
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2) --
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2 + 0.2);
+ \ifthenelse{\n=1}{
+ \draw
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2 + 0.2)
+ node [above] {1.5};
+ }{}
+ } {
+ \ifthenelse{
+ \i=10 \OR \i=20 \OR \i=30 \OR \i=40 \OR
+ \i=60 \OR \i=70 \OR \i=80 \OR \i=90
+ }{
+ \draw[black]
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2) --
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2 + 0.15);
+ } {
+ \draw[black]
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2) --
+ ({#1 + \ciscalefn(\n + \i / 100)}, #2 + 0.1);
+ }
+ }
+ }
+ }
+}
+
+\newcommand{\kscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks 1 - 9
+ \foreach \i in {1,...,9}{
+ \draw[black]
+ ({#1 + \kscalefn(\i)}, #2) --
+ ({#1 + \kscalefn(\i)}, #2 + 0.3)
+ node[above] {\i};
+ }
+ % Numbers and marks 10 - 90
+ \foreach \i in {1,..., 9}{
+ \draw[black]
+ ({#1 + \kscalefn(10 * \i)}, #2) --
+ ({#1 + \kscalefn(10 * \i)}, #2 + 0.3)
+ node[above] {\ifthenelse{\i=10}{1}{\i}};
+ }
+ % Numbers and marks 100 - 1000
+ \foreach \i in {1,..., 10}{
+ \draw[black]
+ ({#1 + \kscalefn(100 * \i)}, #2) --
+ ({#1 + \kscalefn(100 * \i)}, #2 + 0.3)
+ node[above] {\ifthenelse{\i=10}{1}{\i}};
+ }
+
+ % Submarks 1 - 9
+ \foreach \n in {1, ..., 9} {
+ \ifthenelse{\n<4}{
+ \foreach \i in {1,..., 9}
+ } {
+ \foreach \i in {2,4,6,8}
+ }
+ {
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + \kscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \kscalefn(\n + \i / 10)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \kscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \kscalefn(\n + \i / 10)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 10 - 90
+ \foreach \n in {10,20,...,90} {
+ \ifthenelse{\n<40}{
+ \foreach \i in {1,..., 9}
+ } {
+ \foreach \i in {2,4,6,8}
+ }
+ {
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + \kscalefn(\n + \i)}, #2) --
+ ({#1 + \kscalefn(\n + \i)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \kscalefn(\n + \i)}, #2) --
+ ({#1 + \kscalefn(\n + \i)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 100 - 1000
+ \foreach \n in {100,200,...,900} {
+ \ifthenelse{\n<400}{
+ \foreach \i in {10,20,...,90}
+ } {
+ \foreach \i in {20,40,60,80}
+ }
+ {
+ \ifthenelse{\i=50}{
+ \draw[black]
+ ({#1 + \kscalefn(\n + \i)}, #2) --
+ ({#1 + \kscalefn(\n + \i)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \kscalefn(\n + \i)}, #2) --
+ ({#1 + \kscalefn(\n + \i)}, #2 + 0.1);
+ }
+ }
+ }
+}
+
+\newcommand{\lscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks
+ \foreach \i in {0,..., 10}{
+ \draw[black]
+ ({#1 + \lscalefn(\i / 10)}, #2) --
+ ({#1 + \lscalefn(\i / 10)}, #2 + 0.3)
+ node[above] {\ifthenelse{\i=10}{1}{\ifthenelse{\i=0}{0}{.\i}}};
+ }
+
+ % Submarks
+ \foreach \n in {0, ..., 9} {
+ \foreach \i in {1,...,19} {
+ \ifthenelse{\i=10}{
+ \draw[black]
+ ({#1 + \lscalefn((\n + (\i / 20))/10)}, #2) --
+ ({#1 + \lscalefn((\n + (\i / 20))/10)}, #2 + 0.2);
+ } {
+ \ifthenelse{
+ \i=1 \OR \i=3 \OR \i=5 \OR \i=7 \OR
+ \i=9 \OR \i=11 \OR \i=13 \OR \i=15 \OR
+ \i=17 \OR \i=19
+ }{
+ \draw[black]
+ ({#1 + \lscalefn((\n + (\i / 20))/10)}, #2) --
+ ({#1 + \lscalefn((\n + (\i / 20))/10)}, #2 + 0.1);
+ } {
+ \draw[black]
+ ({#1 + \lscalefn((\n + (\i / 20))/10)}, #2) --
+ ({#1 + \lscalefn((\n + (\i / 20))/10)}, #2 + 0.15);
+ }
+ }
+ }
+ }
+}
+
+\newcommand{\tscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+ % First line
+ \draw[black] ({#1}, #2) -- ({#1}, #2 + 0.2);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks 6 - 10
+ \foreach \i in {6,...,9,10,15,...,45}{
+ \draw[black]
+ ({#1 + \tscalefn(\i)}, #2) --
+ ({#1 + \tscalefn(\i)}, #2 + 0.3)
+ node[above] {\i};
+ }
+
+ % Submarks 6 - 10
+ \foreach \n in {6, ..., 9} {
+ \foreach \i in {1,...,9}{
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + \tscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \tscalefn(\n + \i / 10)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \tscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \tscalefn(\n + \i / 10)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 15 - 45
+ \foreach \n in {10, 15, ..., 40} {
+ \foreach \i in {1,...,24}{
+ \ifthenelse{
+ \i=5 \OR \i=10 \OR \i=15 \OR \i=20
+ } {
+ \draw[black]
+ ({#1 + \tscalefn(\n + \i / 5)}, #2) --
+ ({#1 + \tscalefn(\n + \i / 5)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \tscalefn(\n + \i / 5)}, #2) --
+ ({#1 + \tscalefn(\n + \i / 5)}, #2 + 0.1);
+ }
+ }
+ }
+}
+
+\newcommand{\sscale}[3]{
+ \draw[black] ({#1}, #2) -- ({#1 + \sliderulewidth}, #2);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.9);
+ \draw[black] ({#1}, #2 + 0.9) -- ({#1}, #2 + 0.7);
+ \draw[black] ({#1 + \sliderulewidth}, #2 + 0.9) -- ({#1 + \sliderulewidth}, #2 + 0.7);
+
+ % First line
+ \draw[black] ({#1}, #2) -- ({#1}, #2 + 0.2);
+
+
+ \draw ({#1 - 0.1}, #2 + 0.5) node[left] {#3};
+
+ % Numbers and marks
+ \foreach \i in {6,...,9,10,15,...,30,40,50,...,60,90}{
+ \draw[black]
+ ({#1 + \sscalefn(\i)}, #2) --
+ ({#1 + \sscalefn(\i)}, #2 + 0.3)
+ node[above] {\i};
+ }
+
+ % Submarks 6 - 10
+ \foreach \n in {6, ..., 9} {
+ \foreach \i in {1,...,9}{
+ \ifthenelse{\i=5}{
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \sscalefn(\n + \i / 10)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i / 10)}, #2) --
+ ({#1 + \sscalefn(\n + \i / 10)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 15 - 30
+ \foreach \n in {10, 15, ..., 25} {
+ \foreach \i in {1,...,24}{
+ \ifthenelse{
+ \i=5 \OR \i=10 \OR \i=15 \OR \i=20
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i / 5)}, #2) --
+ ({#1 + \sscalefn(\n + \i / 5)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i / 5)}, #2) --
+ ({#1 + \sscalefn(\n + \i / 5)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 30
+ \foreach \n in {30} {
+ \foreach \i in {1,...,19}{
+ \ifthenelse{
+ \i=2 \OR \i=4 \OR \i=6 \OR \i=8 \OR
+ \i=10 \OR \i=12 \OR \i=14 \OR \i=16 \OR
+ \i=18
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i / 2)}, #2) --
+ ({#1 + \sscalefn(\n + \i / 2)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i / 2)}, #2) --
+ ({#1 + \sscalefn(\n + \i / 2)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 40 - 50
+ \foreach \n in {40, 50} {
+ \foreach \i in {1,...,9}{
+ \ifthenelse{
+ \i=5 \OR \i=10 \OR \i=15 \OR \i=20
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i)}, #2) --
+ ({#1 + \sscalefn(\n + \i)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(\n + \i)}, #2) --
+ ({#1 + \sscalefn(\n + \i)}, #2 + 0.1);
+ }
+ }
+ }
+
+ % Submarks 60
+ \foreach \i in {1,...,10}{
+ \ifthenelse{
+ \i=5 \OR \i=10
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(60 + \i * 2)}, #2) --
+ ({#1 + \sscalefn(60 + \i * 2)}, #2 + 0.2);
+ } {
+ \draw[black]
+ ({#1 + \sscalefn(60 + \i * 2)}, #2) --
+ ({#1 + \sscalefn(60 + \i * 2)}, #2 + 0.1);
+ }
+ }
+}