2025-08-25 Functions

  • Review last time

  • Julia intro

  • Julia plotting

  • Floating point numbers

  • Relative & absolute errors

Julia

[1]:
# Note which one gets printed out
x = 13
y = 42
[1]:
42
[2]:
# Semicolons supress output printing
x = 9;
[3]:
# Can also do formatted printing
println("$x + $y = $(x + y)")
9 + 42 = 51
[4]:
# Also have the ability to print the operation and result
# Note the annoying side effect here of the parsing rules
@show x + y
x + y = 51
[4]:
51
[5]:
# And math can be written *as* math
@show area = π * x^2;
area = π * x ^ 2 = 254.46900494077323

Numbers

[6]:
# What are all of these types?
typeof(42), typeof(big(42)), typeof(42.0f0), typeof(42.0), typeof(big(42.0))
[6]:
(Int64, BigInt, Float32, Float64, BigFloat)
[7]:
# What are the promotion rules?
@show 13 + 42.0
@show 13.0f0 + 42.0
@show 13 + 42.0f0;
13 + 42.0 = 55.0
13.0f0 + 42.0 = 55.0
13 + 42.0f0 = 55.0f0
[8]:
# Watch out for division rules
@show 42 / 13
@show 42 ÷ 13;
42 / 13 = 3.230769230769231
42 ÷ 13 = 3
[9]:
# And how integer division works
@show -42 / 13
@show -42 ÷ 13;
-42 / 13 = -3.230769230769231
-42 ÷ 13 = -3

Arrays

[10]:
# Note that changing the type in assigment is ok
x = [1, 2, 3]
[10]:
3-element Vector{Int64}:
 1
 2
 3
[11]:
# But I want floats?
x = Float64[4, 5, 6]
[11]:
3-element Vector{Float64}:
 4.0
 5.0
 6.0
[12]:
# Note promotion rules still work
[1, 2, 3.] + [4, 5, 6]
[12]:
3-element Vector{Float64}:
 5.0
 7.0
 9.0
[13]:
# 1 based indexing scheme (😭)
@show x[2] = 13
typeof(x[2])
x[2] = 13 = 13
[13]:
Float64
[14]:
# And matrixes are 2D arrays
A = [1. 2 3; 4 5 6; 7 8 9]
[14]:
3×3 Matrix{Float64}:
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

Functions

[15]:
# Basic syntax
function f(x, y; z = 3)
    return (x + y) * z
end
[15]:
f (generic function with 1 method)
[16]:
# z is an optional parameter with a default value
@show y1 = f(1, 2)
@show y2 = f(1, 2; z = 4);
y1 = f(1, 2) = 9
y2 = f(1, 2; z = 4) = 12
[17]:
# But what is returned here?
function f(x, y; z = 3)
    (x + y) * z
end
[17]:
f (generic function with 1 method)
[18]:
# Last statement executed in functino return value
@show y1 = f(1, 2)
@show y2 = f(1, 2; z = 4);
y1 = f(1, 2) = 9
y2 = f(1, 2; z = 4) = 12
[19]:
# Function 'assignment form'
f(x, y; z = 3) = (x + y) * z
[19]:
f (generic function with 1 method)
[20]:
# It works the same way - that's comforting
@show y1 = f(1, 2)
@show y2 = f(1, 2; z = 4);
y1 = f(1, 2) = 9
y2 = f(1, 2; z = 4) = 12
[21]:
# Anonymous functions
((x, y; z = 3) -> (x + y) * z)(1, 2; z = 8)
[21]:
24
[22]:
# This is useful in the same way as in Python or JS
map(x -> x^2, [2, 3, 4])
[22]:
3-element Vector{Int64}:
  4
  9
 16
[23]:
[1, 2, 3] .* [4, 5, 6]
[23]:
3-element Vector{Int64}:
  4
 10
 18

Loops

[24]:
# Ranges like in Python or Rust
1:13
[24]:
1:13
[25]:
# Can create arrays this way
collect(1:13.)
[25]:
13-element Vector{Float64}:
  1.0
  2.0
  3.0
  4.0
  5.0
  6.0
  7.0
  8.0
  9.0
 10.0
 11.0
 12.0
 13.0
[26]:
# And for loops use ranges
iterations = 420000
hits = 0
for i in 1:iterations
    hits += (rand()^2 + rand()^2)  1
end
estimate = 4 * hits / iterations
@show π - estimate;
π - estimate = -0.00033115593401644716
[27]:
# List comprehension also works
estimate = sum([1/n^2 for n in 1:13000])
@show π^2 / 6 - estimate;
π ^ 2 / 6 - estimate = 7.692011841831103e-5

Plotting

[28]:
# Need to add package first
using Pkg
pkg"add Plots"
using Plots
default(lw=4, ms=5, legendfontsize=12, xtickfontsize=12, ytickfontsize=12)

a = 1e-15
plot(x -> (1 + x) - 1, xlim=(-a, a))
plot!(x -> x)
    Updating registry at `~/.julia/registries/General.toml`
   Resolving package versions...
  No Changes to `~/.julia/environments/v1.11/Project.toml`
  No Changes to `~/.julia/environments/v1.11/Manifest.toml`
[28]:

Machine precision

Floating point numbers do not exactly represent continuous values.

There exists \(\epsilon_\text{machine}\) such that

\[1 \oplus x = 1\]

for all

\[\lvert x \rvert < \epsilon_\text{machine}\]

Note: \(\oplus, \ominus, \otimes, \oslash\) are the floating point arithmatic versions of \(+, -, \times, /\)

[29]:
# Computing machine precision
ϵ = 1
while 1 + ϵ != 1
    ϵ = ϵ / 2
end

# And lets ask Julia what ϵ actually is
@show ϵ
@show eps();
ϵ = 1.1102230246251565e-16
eps() = 2.220446049250313e-16
[30]:
# But why do we care?
f1(x) = log(1 + x)
f2(x) = x - x^2 / 2 + x^3 / 3 # Taylor series
f3(x) = log1p(x)

plot([f1, f2, f3], xlims=[-5 * ϵ, 5 * ϵ], label=["\$log(1+x)\$" "Taylor series" "\$log1p(x)\$"])
[30]:
[31]:
# How to measure the error?
y1 = f1(1e-8)
y2 = f2(1e-8)

# Absolute
println("absolute error: $(y1 - y2)")

# Relative
println("relative error: $((y1 - y2) / y2)")
absolute error: -6.07747099184471e-17
relative error: -6.077471022232065e-9