Julia Complex Numbers and Rational Numbers
In this section, we will primarily learn about complex and rational numbers in Julia.
Julia's language includes predefined complex and rational number types, and supports various standard mathematical operations and elementary functions for them.
Complex Numbers
Complex numbers are an extension of real numbers, ensuring that every polynomial equation has roots.
A number of the form z=a+bi
(where a and b are real numbers) is called a complex number. Here, a is the real part, b is the imaginary part, and i is the imaginary unit, which has the property
The global constant im is bound to the complex number i, representing the principal square root of -1.
Since Julia allows numeric literals as coefficients of numeric literals, this binding provides a convenient syntax for complex numbers, similar to traditional mathematical notation:
Example
julia> 1+2im
1 + 2im
We can also perform various arithmetic operations on complex numbers:
Example
julia> (1 + 2im)*(2 - 3im)
8 + 1im
julia> (1 + 2im)/(1 - 2im)
-0.6 + 0.8im
julia> (1 + 2im) + (1 - 2im)
2 + 0im
julia> (-3 + 2im) - (5 - 1im)
-8 + 3im
julia> (-1 + 2im)^2
-3 - 4im
julia> (-1 + 2im)^2.5
2.729624464784009 - 6.9606644595719im
julia> (-1 + 2im)^(1 + 1im)
-0.27910381075826657 + 0.08708053414102428im
julia> 3(2 - 5im)
6 - 15im
julia> 3(2 - 5im)^2
-63 - 60im
julia> 3(2 - 5im)^-1.0
0.20689655172413796 + 0.5172413793103449im
The type promotion mechanism also ensures that you can use combinations of operands of different types:
Example
julia> 2(1 - 1im)
2 - 2im
julia> (2 + 3im) - 1
1 + 3im
julia> (1 + 2im) + 0.5
1.5 + 2.0im
julia> (2 + 3im) - 0.5im
2.0 + 2.5im
julia> 0.75(1 + 2im)
0.75 + 1.5im
julia> (2 + 3im) / 2
1.0 + 1.5im
julia> (1 - 3im) / (2 + 2im)
-0.5 - 1.0im
julia> 2im^2
-2 + 0im
julia> 1 + 3/4im
1.0 - 0.75im
Note that 3/4im == 3/(4*im) == -(3/4*im)
because coefficients have higher precedence than division.
Julia provides some standard functions for operating on complex numbers:
Example
julia> z = 1 + 2im
1 + 2im
julia> real(1 + 2im) # real part of z
1
julia> imag(1 + 2im) # imaginary part of z
2
julia> conj(1 + 2im) # complex conjugate of z
1 - 2im
julia> abs(1 + 2im) # absolute value of z
2.23606797749979
julia> abs2(1 + 2im) # squared absolute value
5
julia> angle(1 + 2im) # phase angle in radians
1.1071487177940904
By convention, the absolute value (abs) of a complex number is the distance from zero to it. abs2 gives the square of the absolute value, which is very useful for complex numbers as it avoids taking the square root. angle returns the phase angle in radians (also known as the argument function). All other elementary functions are fully defined for complex numbers:
Example
julia> sqrt(1im)
0.7071067811865476 + 0.7071067811865475im
julia> sqrt(1 + 2im)
1.272019649514069 + 0.7861513777574233im
julia> cos(1 + 2im)
2.0327230070196656 - 3.0518977991517997im
julia> exp(1 + 2im)
-1.1312043837568135 + 2.4717266720048188im
julia> sinh(1 + 2im)
-0.4890562590412937 + 1.4031192506220405im
Note that mathematical functions typically return real values when applied to real numbers and complex values when applied to complex numbers. For example, sqrt behaves differently when applied to -1 and -1 + 0im, even though -1 == -1 + 0im:
Example
julia> sqrt(-1)
ERROR: DomainError with -1.0:
The sqrt
function will only return a complex result if called with a complex argument. Try using sqrt(Complex(x))
.
Stacktrace: [...]
julia> sqrt(-1 + 0im)
0.0 + 1.0im
When constructing complex numbers from variables, the textual numeric coefficient notation is no longer applicable. Instead, multiplication must be explicitly written out:
Example
julia> a = 1; b = 2; a + b*im
1 + 2im
However, this approach is not recommended. Instead, use the more efficient complex
function to directly construct a complex value from the real and imaginary parts:
Example
julia> a = 1; b = 2; complex(a, b)
1 + 2im
This construction avoids multiplication and addition operations.
Inf
and NaN
can appear in the real and imaginary parts of complex numbers, as described in the section on special floating-point values:
Example
julia> 1 + Inf*im
1.0 + Inf*im
julia> 1 + NaN*im
1.0 + NaN*im
Rational Numbers
Rational numbers are the set of all integers (positive, zero, negative) and fractions.
Julia has a rational type to represent the exact ratio of integers. Rationals are constructed using the //
operator:
Example
julia> 2//3
2//3
If the numerator and denominator of a rational have common factors, they are reduced to the simplest form with a non-negative denominator:
Example
julia> 6//9
2//3
julia> -4//8
-1//2
julia> 5//-15
-1//3
julia> -4//-12
1//3
This standardized form of the ratio of integers is unique, so equality of rational values can be tested by checking the equality of the numerator and denominator. The standardized numerator and denominator of a rational can be obtained using the numerator
and denominator
functions:
Example
julia> numerator(2//3)
2
julia> denominator(2//3)
3
Direct comparison of the numerator and denominator is usually unnecessary, as standard arithmetic and comparison operations are defined for rational values:
Example
julia> 2//3 == 6//9
true
julia> 2//3 == 9//27
false
julia> 3//7 < 1//2
true
julia> 3//4 > 2//3
true
julia> 2//4 + 1//6
2//3
julia> 5//12 - 1//4
1//6
julia> 5//8 * 3//12
5//32
julia> 6//5 / 10//7
21//25
Rationals can be easily converted to floating-point numbers:
Example
julia> float(3//4)
0.75
For any integer values a
and b
(except when a == 0
and b == 0
), the conversion from rational to floating-point follows this consistency:
Example
julia> a = 1; b = 2;
julia> isequal(float(a//b), a/b)
true
Julia accepts the construction of infinite rational values:
Example
julia> 5//0
1//0
julia> x = -3//0
-1//0
julia> typeof(x)
Rational{Int64}
However, it does not accept the attempt to construct a NaN
rational value:
Example
julia> 0//0
ERROR: ArgumentError: invalid rational: zero(Int64)//zero(Int64)
Stacktrace:
[...]
As usual, the type promotion system allows rationals to interact easily with other numeric types:
Example
julia> 3//5 + 1
8//5
julia> 3//5 - 0.5
0.09999999999999998
julia> 2//7 * (1 + 2im)
2//7 + 4//7*im
julia> 2//7 * (1.5 + 2im)
0.42857142857142855 + 0.5714285714285714im
julia> 3//2 / (1 + 2im)
3//10 - 3//5*im
julia> 1//2 + 2im
1//2 + 2//1*im
julia> 1 + 2//3im
1//1 - 2//3*im
julia> 0.5 == 1//2
true
julia> 0.33 == 1//3
false
julia> 0.33 < 1//3
true
julia> 1//3 - 0.33
0.0033333333333332993