Book Image

Mastering Julia - Second Edition

By : Malcolm Sherrington
Book Image

Mastering Julia - Second Edition

By: Malcolm Sherrington

Overview of this book

Julia is a well-constructed programming language which was designed for fast execution speed by using just-in-time LLVM compilation techniques, thus eliminating the classic problem of performing analysis in one language and translating it for performance in a second. This book is a primer on Julia’s approach to a wide variety of topics such as scientific computing, statistics, machine learning, simulation, graphics, and distributed computing. Starting off with a refresher on installing and running Julia on different platforms, you’ll quickly get to grips with the core concepts and delve into a discussion on how to use Julia with various code editors and interactive development environments (IDEs). As you progress, you’ll see how data works through simple statistics and analytics and discover Julia's speed, its real strength, which makes it particularly useful in highly intensive computing tasks. You’ll also and observe how Julia can cooperate with external processes to enhance graphics and data visualization. Finally, you will explore metaprogramming and learn how it adds great power to the language and establish networking and distributed computing with Julia. By the end of this book, you’ll be confident in using Julia as part of your existing skill set.
Table of Contents (14 chapters)

Complex and rational numbers

We have met the syntax for rational numbers in the previous chapter, and we will review operations on them here. Also, we will introduce another arithmetic type: complex numbers.

Complex numbers

There are two ways to define a complex number in Julia—first, using the Complex type definition as its associated Complex() constructor:

# Note the difference in these two definitions
julia> c = Complex(1, 2); typeof(c)
Complex{Int64}
julia> c = Complex(1, 2.0); typeof(c)Complex{Float64}
julia> c = ComplexF32(1,2.0); typeof(c)Complex{Float32}

Because in the second example, the complex number consists of an ordered pair of two reals, its size is 128 bits, whereas ComplexF32 has 2x Float32 arguments and ComplexF16 will have 2x Float16 arguments.

The Complex(0.0,1.0) number corresponds to the imaginary number 'I'—that is, sqrt(-1.0)—but Julia uses the 'im' symbol rather than 'I' to avoid confusion with an I variable, frequently used as an index iterator.

Hence, Complex(1, 2) is exactly equivalent to 1 + 2*im, but normally the '*' operator is omitted, and this would be expressed as 1 + 2im.

The complex number supports all normal arithmetic operations, as illustrated here:

julia> c = 1 + 2im;
julia> d = 3 + 4im;
julia> c*d
-5 + 10im
julia> c/d
0.44 + 0.08im
julia> c\d
2.2 - 0.4im

The c/d and c\d divisions produce real arguments even when the components are integers.

This is like Julia’s behavior with a simple division of integers. Also, it defines real(), imag(), conj(), abs(), and angle() complex functions.

abs and angle can be used to convert complex arguments to polar form:

julia> c = 1.0 + 2im; abs(c)
2.23606797749979
julia> angle(c)
1.1071487177940904 # (in radians)

Complex versions of many mathematical functions can be applied:

julia> c = 1 + 2im;
julia> sin(c)
3.1657 + 1.9596im
julia> log(c)
0.8047 + 1.10715im
julia> sqrt(c)
1.272 + 0.78615im

Rationals

Julia has a rational number type to represent exact ratios of integers. A rational is defined by the use of the // operator—for example, 5//7. If the numerator and denominator have a common factor, then the number is reduced to its simplest form; for example, 21//35 reduces to 5//7.

Operations on rationals or on mixed rationals and integers return a rational result:

julia> x = 3; y = 5//7;
julia> x*y
15//7
julia> y^2
25/49
julia> y/x
5//21

The numerator() and denominator() functions return the numerator and denominator of a rational, and float() can be used to convert a rational to a float:

julia> x = 17//100;
julia> numerator(x)
17
julia> denominator(x)
100
julia> float(x) => 0.17

Constructing infinite rational values, both positive and negative, is acceptable:

julia> 5//0
1//0
julia> -5//0
-1//0

Notice that both computations reduce the numerator to 1. It is possible to construct rationals of complex numbers, as in this example:

julia> c = (1 + 2im)//(4 + 3im)
2//5 + 1//5*im

This output is a little confusing as the actual value is (2 + 1im)//5, which arises by multiplying the top and bottom values by the complex conjugate of the denominator (4 – 3im).

The typeof(c) value is Complex{Rational{Int64}}, and as of now, the numerator() and denominator() functions fail, even though these should return (2 + 1im) and 5 respectively:

julia> numerator(c)
ERROR: MethodError: no method matching
       numerator(::Complex{Rational{Int64}})

Closest candidates are:

  numerator(::Integer) at rational.jl:236
  numerator(::Rational) at rational.jl:237