Defining variables in Julia works like in most languages:
int = 4 # An integer
str = "Hi" # A string
float = 1.2 # A floating-point number
bool = true # A boolean (also false)
The type is automatically inferred:
typeof(int)
typeof(str)
typeof(float)
Julia supports a large range of integer and floating-point types out of the box, for example:
x = UInt8(1) # 8-bit wide unsigned integer
y = Int32(-1) # 32-bit wide signed integer
z = Float32(0.2) # single precision
α = Float16(-1.0) # half precision
β = ComplexF64(2. + 8im) # Complex number (composed of two Float64)
Operations between these types may involve automatic promotion.
println(typeof(1 + 1.2))
println(typeof(x * y)) # x was Uint8, y was Int32
x = Float32(1.)
4x # No "*" needed
println(5 % 2)
5^6
2.3^6
println(4 - Float32(2))
println(8 / 3) # Note conversion to Float64
typeof(8 / 3)
This can be avoided using a rational:
x = 6 // 3
println(typeof(x), " ", Int(x))
√2 # == sqrt(2)
Notice the *
operation for string concatenation ...
"Concatenating " * "strings is done " * "using multiplication"
Type conversion is possible, for example using constructors:
Int(2.0)
x = Float32(1.0)
Float64(x)
Int(2.3)
UInt8(-1)
Float64(2.0 + 1im)
Sometimes a special conversion function or syntax exists:
string(1.2)
ceil(Int, 2.3)
round(Int32, 4.5)
x = 1.2
println("x is currently $x.")
println("two less is $(x - 2)")
Arbitrary precision is supported out of the box:
# arbitrary precision
b = big"12"; println(b, " is a ", typeof(b))
f = big"-1.2"; println(f, " is a ", typeof(f))
# Or wir an explicit cast:
b = BigInt(12)
f = BigFloat(-1.2) # Note the difference to the above result
Julia is garbage-collected, meaning that memory occupied by a variable value will be freed automatically if no longer needed, e.g.:
x = 15
println(x)
x = "abc"; # x newly assigned, memory by the "15" will be freed at some point in the future
Unsurprisingly Julia has the standard for
and while
loops and the if
conditionals.
x = 3; y = 5
if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
x = 5
while x > 3
println("Now x is $x")
x -= 1
end
for i in 1:5
println("Hello from number $i")
end
Where the 1:5
is a Range
-object, but it could be any iterable. There are a few syntax variations, including:
accu = 0
for j ∈ 1:0.5:3 # Note the step parameter
accu += j
end
println(accu)
Worth mentioning are also ||
, &&
and ?:
true || println("The RHS of || is only run")
false || println("if the LHS is false")
iseven(3) && println("The RHS of || is only run")
isodd(3) && println("if the LHS is true")
x = 3
x < 5 ? "smaller than 5" : "larger or equal 5"
Generally expressions can be made one block using begin
and end
or (
and )
. The last statement determines the returned value.
z = begin
x = 5
y = -3
x + y
end
# Or equivalently
z = (x = 5; y = -3; x + y)
Compute $$ 15! \qquad 100! \qquad \left(\begin{array}{c} 100 \\ 15 \end{array}\right) $$ with the Julia you know so far.
The Julia standard library is already surprisingly rich in functionality. Features are grouped into smaller packages according to topics (e.g. LinearAlgebra
, SparseArrays
, Test
, ...). The most basic part of the standard library resides in the special package Base
and is always automatically to the programmer. If anything beyond Base
is needed, that is both packages of the standard library or any other third-party package, this needs to be explicitly installed and imported before use.
For example. The randn
function produces a list or array of random numbers. It is already available in Base
and we can thus directly use it to create 4 random numbers:
d = randn(4)
The returned object in d
is an Array
, a type from Base
, which we will discuss later. We wish to create a diagonal Matrix with these four vaules on the diagonal. For this we need the LinearAlgebra.Diagonal
datastructure. We make LinearAlgebra
available to our scope with a using
statement:
using LinearAlgebra
This (might) cause an error, because LinearAlgebra
is not yet installed. We resolve this as recommended:
import Pkg; Pkg.add("LinearAlgebra")
Note, that import
is roughly the same as using
except the package is not brought into scope. We will neglect this detail for this course and just use using
for all packages we use.
Having installed the package, we are able to use LinearAlgebra and make the diagonal matrix:
using LinearAlgebra
Diagonal(d)
Apart from interacting with Julia via a webbrowser and Jupyter (as we will do it in this course). There is also the alternative option to use the Julia REPL. You can get to the REPL by starting julia
from a terminal. The result is a prompt similar to
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.3.0 (2019-11-26)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia>
In this prompt you can directly start typing julia expressions, which will be executed upon [Enter]
. The REPL is very nice to prototype things and with some optional customisations becomes a very powerful tool. We will not use the REPL much in this course, but still I want to mention some basic aspects to get you started. Mostly this is for people who prefer the commandline over graphics (like me):
exit()
or Ctrl + D.[Backspace]
on an empty prompt.Magic key | Prompt | Mode |
---|---|---|
[Backspace] |
julia> |
Julian mode (Command mode) |
] |
(v1.3) pkg> |
Pkg mode |
? |
help> |
Help mode |
; |
shell> |
Shell command mode |
help
once the (v1.3) pkg>
prompt shows.External packages are installed exactly the same as standard library packages. Their data is automatically fetched from the General as needed.
Make sure you have an internet connection. From the REPL or from the notebook, install the following packages as we will need them later:
Plots
Zygote
BenchmarkTools