pdf files; edits
This commit is contained in:
307
quarto/precalc/Precalculus.typ
Normal file
307
quarto/precalc/Precalculus.typ
Normal file
@@ -0,0 +1,307 @@
|
||||
// Some definitions presupposed by pandoc's typst output.
|
||||
#let blockquote(body) = [
|
||||
#set text( size: 0.92em )
|
||||
#block(inset: (left: 1.5em, top: 0.2em, bottom: 0.2em))[#body]
|
||||
]
|
||||
|
||||
#let horizontalrule = [
|
||||
#line(start: (25%,0%), end: (75%,0%))
|
||||
]
|
||||
|
||||
#let endnote(num, contents) = [
|
||||
#stack(dir: ltr, spacing: 3pt, super[#num], contents)
|
||||
]
|
||||
|
||||
#show terms: it => {
|
||||
it.children
|
||||
.map(child => [
|
||||
#strong[#child.term]
|
||||
#block(inset: (left: 1.5em, top: -0.4em))[#child.description]
|
||||
])
|
||||
.join()
|
||||
}
|
||||
|
||||
// Some quarto-specific definitions.
|
||||
|
||||
#show raw.where(block: true): set block(
|
||||
fill: luma(230),
|
||||
width: 100%,
|
||||
inset: 8pt,
|
||||
radius: 2pt
|
||||
)
|
||||
|
||||
#let block_with_new_content(old_block, new_content) = {
|
||||
let d = (:)
|
||||
let fields = old_block.fields()
|
||||
fields.remove("body")
|
||||
if fields.at("below", default: none) != none {
|
||||
// TODO: this is a hack because below is a "synthesized element"
|
||||
// according to the experts in the typst discord...
|
||||
fields.below = fields.below.amount
|
||||
}
|
||||
return block.with(..fields)(new_content)
|
||||
}
|
||||
|
||||
#let unescape-eval(str) = {
|
||||
return eval(str.replace("\\", ""))
|
||||
}
|
||||
|
||||
#let empty(v) = {
|
||||
if type(v) == "string" {
|
||||
// two dollar signs here because we're technically inside
|
||||
// a Pandoc template :grimace:
|
||||
v.matches(regex("^\\s*$")).at(0, default: none) != none
|
||||
} else if type(v) == "content" {
|
||||
if v.at("text", default: none) != none {
|
||||
return empty(v.text)
|
||||
}
|
||||
for child in v.at("children", default: ()) {
|
||||
if not empty(child) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Subfloats
|
||||
// This is a technique that we adapted from https://github.com/tingerrr/subpar/
|
||||
#let quartosubfloatcounter = counter("quartosubfloatcounter")
|
||||
|
||||
#let quarto_super(
|
||||
kind: str,
|
||||
caption: none,
|
||||
label: none,
|
||||
supplement: str,
|
||||
position: none,
|
||||
subrefnumbering: "1a",
|
||||
subcapnumbering: "(a)",
|
||||
body,
|
||||
) = {
|
||||
context {
|
||||
let figcounter = counter(figure.where(kind: kind))
|
||||
let n-super = figcounter.get().first() + 1
|
||||
set figure.caption(position: position)
|
||||
[#figure(
|
||||
kind: kind,
|
||||
supplement: supplement,
|
||||
caption: caption,
|
||||
{
|
||||
show figure.where(kind: kind): set figure(numbering: _ => numbering(subrefnumbering, n-super, quartosubfloatcounter.get().first() + 1))
|
||||
show figure.where(kind: kind): set figure.caption(position: position)
|
||||
|
||||
show figure: it => {
|
||||
let num = numbering(subcapnumbering, n-super, quartosubfloatcounter.get().first() + 1)
|
||||
show figure.caption: it => {
|
||||
num.slice(2) // I don't understand why the numbering contains output that it really shouldn't, but this fixes it shrug?
|
||||
[ ]
|
||||
it.body
|
||||
}
|
||||
|
||||
quartosubfloatcounter.step()
|
||||
it
|
||||
counter(figure.where(kind: it.kind)).update(n => n - 1)
|
||||
}
|
||||
|
||||
quartosubfloatcounter.update(0)
|
||||
body
|
||||
}
|
||||
)#label]
|
||||
}
|
||||
}
|
||||
|
||||
// callout rendering
|
||||
// this is a figure show rule because callouts are crossreferenceable
|
||||
#show figure: it => {
|
||||
if type(it.kind) != "string" {
|
||||
return it
|
||||
}
|
||||
let kind_match = it.kind.matches(regex("^quarto-callout-(.*)")).at(0, default: none)
|
||||
if kind_match == none {
|
||||
return it
|
||||
}
|
||||
let kind = kind_match.captures.at(0, default: "other")
|
||||
kind = upper(kind.first()) + kind.slice(1)
|
||||
// now we pull apart the callout and reassemble it with the crossref name and counter
|
||||
|
||||
// when we cleanup pandoc's emitted code to avoid spaces this will have to change
|
||||
let old_callout = it.body.children.at(1).body.children.at(1)
|
||||
let old_title_block = old_callout.body.children.at(0)
|
||||
let old_title = old_title_block.body.body.children.at(2)
|
||||
|
||||
// TODO use custom separator if available
|
||||
let new_title = if empty(old_title) {
|
||||
[#kind #it.counter.display()]
|
||||
} else {
|
||||
[#kind #it.counter.display(): #old_title]
|
||||
}
|
||||
|
||||
let new_title_block = block_with_new_content(
|
||||
old_title_block,
|
||||
block_with_new_content(
|
||||
old_title_block.body,
|
||||
old_title_block.body.body.children.at(0) +
|
||||
old_title_block.body.body.children.at(1) +
|
||||
new_title))
|
||||
|
||||
block_with_new_content(old_callout,
|
||||
block(below: 0pt, new_title_block) +
|
||||
old_callout.body.children.at(1))
|
||||
}
|
||||
|
||||
// 2023-10-09: #fa-icon("fa-info") is not working, so we'll eval "#fa-info()" instead
|
||||
#let callout(body: [], title: "Callout", background_color: rgb("#dddddd"), icon: none, icon_color: black) = {
|
||||
block(
|
||||
breakable: false,
|
||||
fill: background_color,
|
||||
stroke: (paint: icon_color, thickness: 0.5pt, cap: "round"),
|
||||
width: 100%,
|
||||
radius: 2pt,
|
||||
block(
|
||||
inset: 1pt,
|
||||
width: 100%,
|
||||
below: 0pt,
|
||||
block(
|
||||
fill: background_color,
|
||||
width: 100%,
|
||||
inset: 8pt)[#text(icon_color, weight: 900)[#icon] #title]) +
|
||||
if(body != []){
|
||||
block(
|
||||
inset: 1pt,
|
||||
width: 100%,
|
||||
block(fill: white, width: 100%, inset: 8pt, body))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#let article(
|
||||
title: none,
|
||||
subtitle: none,
|
||||
authors: none,
|
||||
date: none,
|
||||
abstract: none,
|
||||
abstract-title: none,
|
||||
cols: 1,
|
||||
margin: (x: 1.25in, y: 1.25in),
|
||||
paper: "us-letter",
|
||||
lang: "en",
|
||||
region: "US",
|
||||
font: "linux libertine",
|
||||
fontsize: 11pt,
|
||||
title-size: 1.5em,
|
||||
subtitle-size: 1.25em,
|
||||
heading-family: "linux libertine",
|
||||
heading-weight: "bold",
|
||||
heading-style: "normal",
|
||||
heading-color: black,
|
||||
heading-line-height: 0.65em,
|
||||
sectionnumbering: none,
|
||||
toc: false,
|
||||
toc_title: none,
|
||||
toc_depth: none,
|
||||
toc_indent: 1.5em,
|
||||
doc,
|
||||
) = {
|
||||
set page(
|
||||
paper: paper,
|
||||
margin: margin,
|
||||
numbering: "1",
|
||||
)
|
||||
set par(justify: true)
|
||||
set text(lang: lang,
|
||||
region: region,
|
||||
font: font,
|
||||
size: fontsize)
|
||||
set heading(numbering: sectionnumbering)
|
||||
if title != none {
|
||||
align(center)[#block(inset: 2em)[
|
||||
#set par(leading: heading-line-height)
|
||||
#if (heading-family != none or heading-weight != "bold" or heading-style != "normal"
|
||||
or heading-color != black or heading-decoration == "underline"
|
||||
or heading-background-color != none) {
|
||||
set text(font: heading-family, weight: heading-weight, style: heading-style, fill: heading-color)
|
||||
text(size: title-size)[#title]
|
||||
if subtitle != none {
|
||||
parbreak()
|
||||
text(size: subtitle-size)[#subtitle]
|
||||
}
|
||||
} else {
|
||||
text(weight: "bold", size: title-size)[#title]
|
||||
if subtitle != none {
|
||||
parbreak()
|
||||
text(weight: "bold", size: subtitle-size)[#subtitle]
|
||||
}
|
||||
}
|
||||
]]
|
||||
}
|
||||
|
||||
if authors != none {
|
||||
let count = authors.len()
|
||||
let ncols = calc.min(count, 3)
|
||||
grid(
|
||||
columns: (1fr,) * ncols,
|
||||
row-gutter: 1.5em,
|
||||
..authors.map(author =>
|
||||
align(center)[
|
||||
#author.name \
|
||||
#author.affiliation \
|
||||
#author.email
|
||||
]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if date != none {
|
||||
align(center)[#block(inset: 1em)[
|
||||
#date
|
||||
]]
|
||||
}
|
||||
|
||||
if abstract != none {
|
||||
block(inset: 2em)[
|
||||
#text(weight: "semibold")[#abstract-title] #h(1em) #abstract
|
||||
]
|
||||
}
|
||||
|
||||
if toc {
|
||||
let title = if toc_title == none {
|
||||
auto
|
||||
} else {
|
||||
toc_title
|
||||
}
|
||||
block(above: 0em, below: 2em)[
|
||||
#outline(
|
||||
title: toc_title,
|
||||
depth: toc_depth,
|
||||
indent: toc_indent
|
||||
);
|
||||
]
|
||||
}
|
||||
|
||||
if cols == 1 {
|
||||
doc
|
||||
} else {
|
||||
columns(cols, doc)
|
||||
}
|
||||
}
|
||||
|
||||
#set table(
|
||||
inset: 6pt,
|
||||
stroke: none
|
||||
)
|
||||
|
||||
#show: doc => article(
|
||||
title: [Precalculus topics with Julia],
|
||||
date: [2024-10-13],
|
||||
sectionnumbering: "1.",
|
||||
toc_title: [Table of contents],
|
||||
toc_depth: 3,
|
||||
cols: 1,
|
||||
doc,
|
||||
)
|
||||
|
||||
|
||||
Various pre-calculus topics
|
||||
15
quarto/precalc/Project.toml
Normal file
15
quarto/precalc/Project.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[deps]
|
||||
CalculusWithJulia = "a2e0e22d-7d4c-5312-9169-8b992201a882"
|
||||
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
||||
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
|
||||
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
|
||||
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
|
||||
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
|
||||
PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
|
||||
PlotlyKaleido = "f2990250-8cf9-495f-b13a-cce12b45703c"
|
||||
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
|
||||
Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45"
|
||||
Primes = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae"
|
||||
RealPolynomialRoots = "87be438c-38ae-47c4-9398-763eabe5c3be"
|
||||
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
|
||||
SymPy = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6"
|
||||
1
quarto/precalc/_pdf_index.qmd
Symbolic link
1
quarto/precalc/_pdf_index.qmd
Symbolic link
@@ -0,0 +1 @@
|
||||
../precalc.qmd
|
||||
@@ -440,7 +440,7 @@ This follows usual mathematical convention, but is a source of potential confusi
|
||||
On the Google calculator, the square root button has a single purpose: for the current value find a square root if possible, and if not signal an error (such as what happens if the value is negative). For more general powers, the $x^y$ key can be used.
|
||||
|
||||
|
||||
In `Julia`, functions are used to perform the actions that a specialized button may do on the calculator. `Julia` provides many standard mathematical functions - more than there could be buttons on a calculator - and allows the user to easily define their own functions. For example, `Julia` provides the same set of functions as on Google's calculator, though with different names. For logarithms, $\ln$ becomes `log` and $\log$ is `log10` (computer programs almost exclusively reserve `log` for the natural log); for factorials, $x!$, there is `factorial`; for powers $\sqrt{}$ becomes `sqrt`, $EXP$ becomes `exp`, and $x^y$ is computed with the infix operator `^`. For the trigonometric functions, the basic names are similar: `sin`, `cos`, `tan`. These expect radians. For angles in degrees, the convenience functions `sind`, `cosd`, and `tand` are provided. On the calculator, inverse functions like $\sin^{-1}(x)$ are done by combining $Inv$ with $\sin$. With `Julia`, the function name is `asin`, an abbreviation for "arcsine." (Which is a good thing, as the notation using a power of $-1$ is often a source of confusion and is not supported by `Julia` without work.) Similarly, there are `asind`, `acos`, `acosd`, `atan`, and `atand` functions available to the `Julia` user.
|
||||
In `Julia`, functions are used to perform the actions that a specialized button may do on the calculator. `Julia` provides many standard mathematical functions - more than there could be buttons on a calculator - and allows the user to easily define their own functions. For example, `Julia` provides the same set of functions as on Google's calculator, though with different names. For logarithms, $\ln$ becomes `log` and $\log$ is `log10` (computer programs almost exclusively reserve `log` for the natural log); for factorials, $x!$, there is `factorial`; for powers $\sqrt{...}$ becomes `sqrt`, $EXP$ becomes `exp`, and $x^y$ is computed with the infix operator `^`. For the trigonometric functions, the basic names are similar: `sin`, `cos`, `tan`. These expect radians. For angles in degrees, the convenience functions `sind`, `cosd`, and `tand` are provided. On the calculator, inverse functions like $\sin^{-1}(x)$ are done by combining $Inv$ with $\sin$. With `Julia`, the function name is `asin`, an abbreviation for "arcsine." (Which is a good thing, as the notation using a power of $-1$ is often a source of confusion and is not supported by `Julia` without work.) Similarly, there are `asind`, `acos`, `acosd`, `atan`, and `atand` functions available to the `Julia` user.
|
||||
|
||||
|
||||
The following table summarizes the above:
|
||||
@@ -452,7 +452,7 @@ using DataFrames
|
||||
calc = [
|
||||
L" $+$, $-$, $\times$, $\div$",
|
||||
L"x^y",
|
||||
L"\sqrt{}, \sqrt[3]{}",
|
||||
L"\sqrt{...}, \sqrt[3]{...}",
|
||||
L"e^x",
|
||||
L" $\ln$, $\log$",
|
||||
L"\sin, \cos, \tan, \sec, \csc, \cot",
|
||||
|
||||
@@ -1289,11 +1289,11 @@ import IntervalArithmetic
|
||||
```
|
||||
|
||||
```{julia}
|
||||
I1 = IntervalArithmetic.Interval(-Inf, Inf)
|
||||
I1 = IntervalArithmetic.interval(-Inf, Inf)
|
||||
```
|
||||
|
||||
```{julia}
|
||||
I2 = IntervalArithmetic.Interval(0, Inf)
|
||||
I2 = IntervalArithmetic.interval(0, Inf)
|
||||
```
|
||||
|
||||
The main feature of the package is not to construct intervals, but rather to *rigorously* bound with an interval the output of the image of a closed interval under a function. That is, for a function $f$ and *closed* interval $[a,b]$, a bound for the set $\{f(x) \text{ for } x \text{ in } [a,b]\}$. When `[a,b]` is the domain of $f$, then this is a bound for the range of $f$.
|
||||
@@ -1303,7 +1303,7 @@ For example the function $f(x) = x^2 + 2$ had a domain of all real $x$, the rang
|
||||
|
||||
|
||||
```{julia}
|
||||
ab = IntervalArithmetic.Interval(-Inf, Inf)
|
||||
ab = IntervalArithmetic.interval(-Inf, Inf)
|
||||
u(x) = x^2 + 2
|
||||
u(ab)
|
||||
```
|
||||
@@ -1344,7 +1344,7 @@ Now consider the evaluation
|
||||
```{julia}
|
||||
#| hold: true
|
||||
f(x) = x^x
|
||||
I = IntervalArithmetic.Interval(0, Inf)
|
||||
I = IntervalArithmetic.interval(0, Inf)
|
||||
f(I)
|
||||
```
|
||||
|
||||
|
||||
@@ -182,11 +182,13 @@ Finally, let's investigate the fact that the harmonic mean, $2/(1/a + 1/b)$ is l
|
||||
|
||||
```{julia}
|
||||
#| hold: true
|
||||
a, b = rand(2)
|
||||
h = 2 / (1/a + 1/b)
|
||||
g = (a * b) ^ (1 / 2)
|
||||
q = sqrt((a^2 + b^2) / 2)
|
||||
h <= g, g <= q
|
||||
let
|
||||
a, b = rand(2)
|
||||
h = 2 / (1/a + 1/b)
|
||||
g = (a * b) ^ (1 / 2)
|
||||
q = sqrt((a^2 + b^2) / 2)
|
||||
h <= g, g <= q
|
||||
end
|
||||
```
|
||||
|
||||
## Chaining, combining expressions: absolute values
|
||||
|
||||
27
quarto/precalc/make_pdf.jl
Normal file
27
quarto/precalc/make_pdf.jl
Normal file
@@ -0,0 +1,27 @@
|
||||
module Make
|
||||
# makefile for generating typst pdfs
|
||||
# per directory usage
|
||||
dir = "precalc"
|
||||
files = ("calculator",
|
||||
"variables",
|
||||
"numbers_types",
|
||||
"logical_expressions",
|
||||
"vectors",
|
||||
"ranges",
|
||||
"functions",
|
||||
"plotting",
|
||||
"transformations",
|
||||
"inversefunctions",
|
||||
"polynomial",
|
||||
"polynomial_roots",
|
||||
"polynomials_package",
|
||||
"rational_functions",
|
||||
"exp_log_functions",
|
||||
"trig_functions",
|
||||
"julia_overview"
|
||||
)
|
||||
|
||||
include("../_make_pdf.jl")
|
||||
main()
|
||||
|
||||
end
|
||||
@@ -481,7 +481,7 @@ Now consider the related polynomial, $q$, where we multiply $p$ by $x^n$ and sub
|
||||
#| hold: true
|
||||
p = a*x^2 + b*x + c
|
||||
n = 2 # the degree of p
|
||||
q = expand(x^n * p(x => 1/x))
|
||||
expand(x^n * p(x => 1/x))
|
||||
```
|
||||
|
||||
In particular, from the reversal, the behavior of $q$ for large $x$ depends on the sign of $a_0$. As well, due to the $1/x$, the behaviour of $q$ for large $x>0$ is the same as the behaviour of $p$ for small *positive* $x$. In particular if $a_n > 0$ but $a_0 < 0$, then `p` is eventually positive and `q` is eventually negative.
|
||||
|
||||
@@ -381,8 +381,8 @@ For a polynomial with symbolic coefficients, the difference between the symbol a
|
||||
#| hold: true
|
||||
@syms a b c
|
||||
p = a*x^2 + b*x + c
|
||||
q = sympy.Poly(p, x) # identify `x` as indeterminate; alternatively p.as_poly(x)
|
||||
roots(q)
|
||||
q1 = sympy.Poly(p, x) # identify `x` as indeterminate; alternatively p.as_poly(x)
|
||||
roots(q1)
|
||||
```
|
||||
|
||||
:::{.callout-note}
|
||||
|
||||
@@ -660,3 +660,51 @@ The [product](http://en.wikipedia.org/wiki/Arithmetic_progression) of the terms
|
||||
val = prod(1:2:19)
|
||||
numericq(val)
|
||||
```
|
||||
|
||||
##### Question
|
||||
|
||||
Credit card numbers have a check digit to ensure data entry of a 16-digit number is correct. How does it work? The [Luhn Alogorithm](https://en.wikipedia.org/wiki/Luhn_algorithm).
|
||||
|
||||
Let's see if `4137 8947 1175 5804` is a valid credit card number?
|
||||
|
||||
First, we enter it as a value and immediately break the number into its digits:
|
||||
|
||||
```{julia}
|
||||
x = 4137_8947_1175_5904 # _ in a number is ignored by parser
|
||||
xs = digits(x)
|
||||
```
|
||||
|
||||
We reverse the order, so the first number in digits is the largest place value in `xs`
|
||||
|
||||
```{julia}
|
||||
reverse!(xs)
|
||||
```
|
||||
|
||||
Now, the 1st, 3rd, 5th, ... digit is doubled. We do this through indexing:
|
||||
|
||||
```{julia}
|
||||
for i in 1:2:length(xs)
|
||||
xs[i] = 2 * xs[i]
|
||||
end
|
||||
```
|
||||
|
||||
Number greater than 9, have their digits added, then all the resulting numbers are added. This can be done with a generator:
|
||||
|
||||
|
||||
```{julia}
|
||||
z = sum(sum(digits(xi)) for xi in xs)
|
||||
```
|
||||
|
||||
If this sum has a remainder of 0 when dividing by 10, the credit card number is possibly valid, if not it is definitely invalid. (The check digit is the last number and is set so that the above applied to the first 15 digits *plus* the check digit results in a multiple of 10.)
|
||||
|
||||
```{julia}
|
||||
iszero(rem(z,10))
|
||||
```
|
||||
|
||||
Darn. A typo. is `4137 8947 1175 5804` a possible credit card number?
|
||||
|
||||
```{julia}
|
||||
#| hold: true
|
||||
#| echo: false
|
||||
booleanq(true)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user