503 lines
14 KiB
Plaintext
503 lines
14 KiB
Plaintext
# Variables
|
|
|
|
## Assignment
|
|
|
|
```julia; echo=false; results="hidden"
|
|
using CalculusWithJulia
|
|
using CalculusWithJulia.WeaveSupport
|
|
|
|
const frontmatter = (
|
|
title = "Variables",
|
|
description = "Calculus with Julia: Variables",
|
|
tags = ["CalculusWithJulia", "precalc", "variables"],
|
|
);
|
|
|
|
nothing
|
|
```
|
|
|
|
```julia; echo=false;
|
|
imgfile = "figures/calculator.png"
|
|
caption = "Screenshot of a calculator provided by the Google search engine."
|
|
ImageFile(:precalc, imgfile, caption)
|
|
```
|
|
|
|
|
|
The Google calculator has a button `Ans` to refer to the answer to the
|
|
previous evaluation. This is a form of memory. The last answer is
|
|
stored in a specific place in memory for retrieval when `Ans` is
|
|
used. In some calculators, more advanced memory features are
|
|
possible. For some, it is possible to push values onto a stack of
|
|
values for them to be referred to at a later time. This proves useful
|
|
for complicated expressions, say, as the expression can be broken into
|
|
smaller intermediate steps to be computed. These values can then be
|
|
appropriately combined. This strategy is a good one, though the memory
|
|
buttons can make its implementation a bit cumbersome.
|
|
|
|
With `Julia`, as with other programming languages, it is very easy to
|
|
refer to past evaluations. This is done by *assignment* whereby a
|
|
computed value stored in memory is associated with a name. The name
|
|
can be used to look up the value later. Assignment does not change the value of the object being assigned, it only introduces a reference to it.
|
|
|
|
Assignment in `Julia` is handled by the equals sign and takes the general form `variable_name = value`. For example, here we assign values to the variables `x` and `y`
|
|
|
|
|
|
```julia;
|
|
x = sqrt(2)
|
|
y = 42
|
|
```
|
|
|
|
In an assignment, the right hand side is always returned, so it appears
|
|
nothing has happened. However, the values are there, as can be checked
|
|
by typing their name
|
|
|
|
```julia;
|
|
x
|
|
```
|
|
|
|
|
|
Just typing a variable name (without a trailing semicolon) causes the assigned value to be displayed.
|
|
|
|
|
|
Variable names can be reused, as here, where we redefine `x`:
|
|
|
|
```julia;hold=true
|
|
x = 2
|
|
```
|
|
|
|
```julia; echo=false
|
|
note("""
|
|
The `Pluto` interface for `Julia` is idiosyncratic, as variables are *reactive*. This interface allows changes to a variable `x` to propogate to all other cells referring to `x`. Consequently, the variable name can only be assigned *once* per notebook **unless** the name is in some other namespace, which can be arranged by including the assignment inside a function or a `let` block.
|
|
""")
|
|
```
|
|
|
|
|
|
`Julia` is referred to as a "dynamic language" which means (in most
|
|
cases) that a variable can be reassigned with a value of a different
|
|
type, as we did with `x` where first it was assigned to a floating
|
|
point value then to an integer value. (Though we meet some cases - generic functions - where `Julia`
|
|
balks at reassigning a variable if the type if different.)
|
|
|
|
|
|
|
|
|
|
More importantly than displaying a value, is the use of variables to
|
|
build up more complicated expressions. For example, to compute
|
|
|
|
```math
|
|
\frac{1 + 2 \cdot 3^4}{5 - 6/7}
|
|
```
|
|
|
|
we might break it into the grouped pieces implied by the mathematical notation:
|
|
|
|
```julia;
|
|
top = 1 + 2*3^4
|
|
bottom = 5 - 6/7
|
|
top/bottom
|
|
```
|
|
|
|
#### Examples
|
|
|
|
##### Example
|
|
|
|
Imagine we have the following complicated expression related to the trajectory of a [projectile](http://www.researchgate.net/publication/230963032_On_the_trajectories_of_projectiles_depicted_in_early_ballistic_woodcuts) with wind resistance:
|
|
|
|
```math
|
|
\left(\frac{g}{k v_0\cos(\theta)} + \tan(\theta) \right) t + \frac{g}{k^2}\ln\left(1 - \frac{k}{v_0\cos(\theta)} t \right)
|
|
```
|
|
|
|
Here $g$ is the gravitational constant $9.8$ and $v_0$, $\theta$ and
|
|
$k$ parameters, which we take to be $200$, $45$ degrees, and $1/2$
|
|
respectively. With these values, the above expression can be computed
|
|
when $s=100$:
|
|
|
|
```julia;
|
|
g = 9.8
|
|
v0 = 200
|
|
theta = 45
|
|
k = 1/2
|
|
t = 100
|
|
a = v0 * cosd(theta)
|
|
(g/(k*a) + tand(theta))* t + (g/k^2) * log(1 - (k/a)*t)
|
|
```
|
|
|
|
By defining a new variable `a` to represent a value that is repeated a few times in the expression, the last command is greatly simplified. Doing so makes it much easier to check for accuracy against the expression to compute.
|
|
|
|
##### Example
|
|
|
|
A common expression in mathematics is a polynomial expression, for example $-16s^2 + 32s - 12$. Translating this to `Julia` at $s =3$ we might have:
|
|
|
|
```julia;
|
|
s = 3
|
|
-16*s^2 + 32*s - 12
|
|
```
|
|
|
|
This looks nearly identical to the mathematical expression, but we inserted `*` to indicate multiplication between the constant and the variable. In fact, this step is not needed as Julia allows numeric literals to have an implied multiplication:
|
|
|
|
```julia;
|
|
-16s^2 + 32s - 12
|
|
```
|
|
|
|
|
|
|
|
|
|
## Where math and computer notations diverge
|
|
|
|
It is important to recognize that `=` to `Julia` is not in analogy to
|
|
how $=$ is used in mathematical notation. The following `Julia` code
|
|
is not an equation:
|
|
|
|
```julia;hold=true
|
|
x = 3
|
|
x = x^2
|
|
```
|
|
|
|
What happens instead? The right hand side is evaluated (`x` is
|
|
squared), the result is stored and bound to the variable `x` (so that
|
|
`x` will end up pointing to the new value, `9`, and not the original one, `3`); finally the value computed on the
|
|
right-hand side is returned and in this case displayed, as there is no
|
|
trailing semicolon to suppress the output.
|
|
|
|
This is completely unlike the mathematical equation $x = x^2$ which is
|
|
typically solved for values of $x$ that satisfy the equation ($0$ and
|
|
$1$).
|
|
|
|
##### Example
|
|
|
|
Having `=` as assignment is usefully exploited when modeling
|
|
sequences. For example, an application of Newton's method might end up
|
|
with this expression:
|
|
|
|
```math
|
|
x_{i+1} = x_i - \frac{x_i^2 - 2}{2x_i}
|
|
```
|
|
|
|
As a mathematical expression, for each $i$ this defines a new value
|
|
for $x_{i+1}$ in terms of a known value $x_i$. This can be used to
|
|
recursively generate a sequence, provided some starting point is
|
|
known, such as $x_0 = 2$.
|
|
|
|
The above might be written instead with:
|
|
|
|
```julia;hold=true
|
|
x = 2
|
|
x = x - (x^2 - 2) / (2x)
|
|
x = x - (x^2 - 2) / (2x)
|
|
```
|
|
|
|
Repeating this last line will generate new values of `x` based on the
|
|
previous one - no need for subscripts. This is exactly what the
|
|
mathematical notation indicates is to be done.
|
|
|
|
## Context
|
|
|
|
The binding of a value to a variable name happens within some
|
|
context. For our simple illustrations, we are assigning values, as
|
|
though they were typed at the command line. This stores the binding in
|
|
the `Main` module. `Julia` looks for variables in this module when it
|
|
encounters an expression and the value is substituted. Other uses, such as when variables are defined within a function, involve different contexts which may not be
|
|
visible within the `Main` module.
|
|
|
|
```julia; echo=false;
|
|
note("""
|
|
The `varinfo` function will list the variables currently defined in the
|
|
main workspace. There is no mechanism to delete a single variable.
|
|
""")
|
|
```
|
|
|
|
```julia; echo=false;
|
|
alert("""
|
|
**Shooting oneselves in the foot.** `Julia` allows us to locally
|
|
redefine variables that are built in, such as the value for `pi` or
|
|
the function object assigned to `sin`. For example, this is a
|
|
perfectly valid command `sin=3`. However, it will overwrite the
|
|
typical value of `sin` so that `sin(3)` will be an error. At the terminal, the
|
|
binding to `sin` occurs in the `Main` module. This shadows that
|
|
value of `sin` bound in the `Base` module. Even if redefined in
|
|
`Main`, the value in base can be used by fully qualifying the name,
|
|
as in `Base.sin(pi)`. This uses the notation
|
|
`module_name.variable_name` to look up a binding in a module.
|
|
""")
|
|
```
|
|
|
|
## Variable names
|
|
|
|
`Julia` has a very wide set of possible
|
|
[names](https://docs.julialang.org/en/stable/manual/variables/#Allowed-Variable-Names-1)
|
|
for variables. Variables are case sensitive and their names can
|
|
include many
|
|
[Unicode](http://en.wikipedia.org/wiki/List_of_Unicode_characters)
|
|
characters. Names must begin with a letter or an appropriate Unicode
|
|
value (but not a number). There are some reserved words, such as `try`
|
|
or `else` which can not be assigned to. However, many built-in names
|
|
can be locally overwritten. Conventionally, variable names are lower
|
|
case. For compound names, it is not unusual to see them squished
|
|
together, joined with underscores, or written in camelCase.
|
|
|
|
```julia;
|
|
value_1 = 1
|
|
a_long_winded_variable_name = 2
|
|
sinOfX = sind(45)
|
|
__private = 2 # a convention
|
|
```
|
|
|
|
### Unicode names
|
|
|
|
Julia allows variable names to use Unicode identifiers. Such
|
|
names allow `julia` notation to mirror that of many
|
|
mathematical texts. For example, in calculus the variable $\epsilon$
|
|
is often used to represent some small number. We can assign to a
|
|
symbol that looks like $\epsilon$ using `Julia`'s LaTeX input
|
|
mode. Typing `\epsilon[tab]` will replace the text with the symbol
|
|
within `IJulia` or the command line.
|
|
|
|
```julia;
|
|
ϵ = 1e-10
|
|
```
|
|
|
|
|
|
Entering Unicode names follows the pattern of
|
|
"slash" + LaTeX name + `[tab]` key. Some other ones that are useful
|
|
are `\delta[tab]`, `\alpha[tab]`, and `\beta[tab]`, though there are
|
|
[hundreds](https://github.com/JuliaLang/julia/blob/master/stdlib/REPL/src/latex_symbols.jl)
|
|
of other values defined.
|
|
|
|
|
|
For example, we could have defined `theta` (`\theta[tab]`) and `v0` (`v\_0[tab]`) using Unicode to make them match more closely the typeset math:
|
|
|
|
```julia;
|
|
θ = 45; v₀ = 200
|
|
```
|
|
|
|
These notes often use Unicode alternatives to avoid the `Pluto` requirement of a single use of assigning to a variable name in a notebook without placing the assignment in a `let` block or a function body.
|
|
|
|
|
|
```julia; echo=false;
|
|
alert("""
|
|
There is even support for tab-completion of
|
|
[emojis](https://github.com/JuliaLang/julia/blob/master/stdlib/REPL/src/emoji_symbols.jl)
|
|
such as `\\:snowman:[tab]` or `\\:koala:[tab]`
|
|
|
|
""")
|
|
```
|
|
|
|
##### Example
|
|
|
|
As mentioned the value of $e$ is bound to the Unicode value
|
|
`\euler[tab]` and not the letter `e`, so Unicode entry is required to
|
|
access this constant This isn't quite true. The `MathConstants` module
|
|
defines `e`, as well as a few other values accessed via Unicode. When
|
|
the `CalculusWithJulia` package is loaded, as will often be done in
|
|
these notes, a value of `exp(1)` is assigned to `e`.
|
|
|
|
|
|
|
|
## Tuple assignment
|
|
|
|
It is a common task to define more than one variable. Multiple definitions can be done in one line, using semicolons to break up the commands, as with:
|
|
|
|
```julia;hold=true
|
|
a = 1; b = 2; c=3
|
|
```
|
|
|
|
|
|
|
|
For convenience, `Julia` allows an alternate means to define more than one variable at a time. The syntax is similar:
|
|
|
|
```julia;hold=true
|
|
a, b, c = 1, 2, 3
|
|
b
|
|
```
|
|
|
|
This sets `a=1`, `b=2`, and `c=3`, as suggested. This construct relies
|
|
on *tuple destructuring*. The expression on the right hand side forms
|
|
a tuple of values. A tuple is a container for different types of
|
|
values, and in this case the tuple has 3 values. When the same number
|
|
of variables match on the left-hand side as those in the container on
|
|
the right, the names are assigned one by one.
|
|
|
|
The value on the right hand side is evaluated, then the assignment occurs. The following exploits this to swap the values assigned to `a` and `b`:
|
|
|
|
```julia;hold=true
|
|
a, b = 1, 2
|
|
a, b = b, a
|
|
```
|
|
|
|
#### Example, finding the slope
|
|
|
|
Find the slope of the line connecting the points $(1,2)$ and $(4,6)$. We begin by defining the values and then applying the slope formula:
|
|
|
|
```julia;
|
|
x0, y0 = 1, 2
|
|
x1, y1 = 4, 6
|
|
m = (y1 - y0) / (x1 - x0)
|
|
```
|
|
|
|
Of course, this could be computed directly with `(6-2) / (4-1)`, but by using familiar names for the values we can be certain we apply the formula properly.
|
|
|
|
|
|
|
|
## Questions
|
|
|
|
###### Question
|
|
|
|
Let $a=10$, $b=2.3$, and $c=8$. Find the value of $(a-b)/(a-c)$.
|
|
|
|
```julia; hold=true; echo=false;
|
|
a,b,c = 10, 2.3, 8;
|
|
numericq((a-b)/(a-c))
|
|
```
|
|
|
|
|
|
###### Question
|
|
|
|
Let `x = 4`. Compute $y=100 - 2x - x^2$. What is the value:
|
|
|
|
```julia; hold=true; echo=false;
|
|
x = 4
|
|
y =- 100 - 2x - x^2
|
|
numericq(y, 0.1)
|
|
```
|
|
|
|
|
|
###### Question
|
|
|
|
What is the answer to this computation?
|
|
|
|
```julia; eval=false
|
|
a = 3.2; b=2.3
|
|
a^b - b^a
|
|
```
|
|
|
|
|
|
```julia; hold=true; echo=false;
|
|
a = 3.2; b=2.3;
|
|
val = a^b - b^a;
|
|
numericq(val)
|
|
```
|
|
|
|
|
|
###### Question
|
|
|
|
For longer computations, it can be convenient to do them in parts, as
|
|
this makes it easier to check for mistakes.
|
|
|
|
For example, to compute
|
|
|
|
```math
|
|
\frac{p - q}{\sqrt{p(1-p)}}
|
|
```
|
|
|
|
for $p=0.25$ and $q=0.2$ we might do:
|
|
|
|
|
|
|
|
```julia; eval=false
|
|
p, q = 0.25, 0.2
|
|
top = p - q
|
|
bottom = sqrt(p*(1-p))
|
|
ans = top/bottom
|
|
```
|
|
|
|
What is the result of the above?
|
|
|
|
```julia; hold=true; echo=false;
|
|
p, q = 0.25, 0.2;
|
|
top = p - q;
|
|
bottom = sqrt(p*(1-p));
|
|
ans = top/bottom;
|
|
numericq(ans)
|
|
```
|
|
|
|
###### Question
|
|
|
|
Using variables to record the top and the bottom of the expression, compute the following for $x=3$:
|
|
|
|
```math
|
|
y = \frac{x^2 - 2x - 8}{x^2 - 9x - 20}.
|
|
```
|
|
|
|
```julia; hold=true; echo=false;
|
|
x = 3
|
|
val = (x^2 - 2x - 8)/(x^2 - 9x - 20)
|
|
numericq(val)
|
|
```
|
|
|
|
###### Question
|
|
|
|
Which if these is not a valid variable name (identifier) in `Julia`:
|
|
|
|
```julia; hold=true; echo=false;
|
|
choices = [
|
|
q"5degreesbelowzero",
|
|
q"some_really_long_name_that_is_no_fun_to_type",
|
|
q"aMiXeDcAsEnAmE",
|
|
q"fahrenheit451"
|
|
]
|
|
ans = 1
|
|
radioq(choices, ans)
|
|
```
|
|
|
|
|
|
|
|
###### Question
|
|
|
|
Which of these symbols is one of `Julia`'s built-in math constants?
|
|
|
|
```julia; hold=true; echo=false;
|
|
choices = [q"pi", q"oo", q"E", q"I"]
|
|
ans = 1
|
|
radioq(choices, ans)
|
|
```
|
|
|
|
|
|
|
|
###### Question
|
|
|
|
What key sequence will produce this assignment
|
|
|
|
```julia; eval=false
|
|
δ = 1/10
|
|
```
|
|
|
|
```julia; hold=true; echo=false;
|
|
choices=[
|
|
q"\delta[tab] = 1/10",
|
|
q"delta[tab] = 1/10",
|
|
q"$\\delta$ = 1/10"]
|
|
ans = 1
|
|
radioq(choices, ans)
|
|
```
|
|
|
|
|
|
###### Question
|
|
|
|
Which of these three statements will **not** be a valid way to assign three variables at once:
|
|
|
|
```julia; hold=true; echo=false;
|
|
choices = [
|
|
q"a=1, b=2, c=3",
|
|
q"a,b,c = 1,2,3",
|
|
q"a=1; b=2; c=3"]
|
|
ans = 1
|
|
radioq(choices, ans)
|
|
```
|
|
|
|
###### Question
|
|
|
|
The fact that assignment *always* returns the value of the right hand side *and* the fact that the `=` sign associates from right to left means that the following idiom:
|
|
|
|
```julia; eval=false
|
|
x = y = z = 3
|
|
```
|
|
|
|
Will always:
|
|
|
|
```julia; hold=true; echo=false;
|
|
choices = ["Assign all three variables at once to a value of `3`",
|
|
"Create ``3`` linked values that will stay synced when any value changes",
|
|
"Throw an error"
|
|
]
|
|
ans = 1
|
|
radioq(choices, ans)
|
|
```
|