If your background includes mathematics or physics, you’ve no doubt encountered complex numbers. The basic unit used in complex numbers is the square root of , denoted in mathematics and physics books by a lowercase , and in engineering by . Any number that is a multiple of is called an imaginary number. A complex number is the sum of a real number and an imaginary number, as in or . [As my background is in physics, I tend to prefer over , but we’ll have to overcome that predilection when we program in Python, as we’ll see.]
Python uses an upper or lowercase ‘J’ or ‘j’ to denote . Thus we can define the above complex numbers in Python as:
z1 = 3 + 4j z2 = -7.2 - 9.3j
If the real or imaginary part of a complex number contains a decimal point, it is stored as a float, so the usual problems with roundoff error can occur with complex numbers as well. Note that if you want to use the quantity on its own, you must prefix it with 1, as in
z = 1j. The letter ‘j’ on its own is interpreted as a variable name.
All the basic arithmetic operations are defined for complex numbers. As a reminder, the arithmetic operations are defined as follows for complex numbers and :
Try these to see what you get:
z1 + z2 z1 - z2 z1 * z2 z1 / z2See answers
Note that the integer division operator // is not defined for complex numbers.
To do more advanced operations on complex numbers, you’ll need the
cmath module. This allows you to express a complex number z in polar form as , where is the modulus or amplitude of z (written ) and is the phase. You can also apply standard functions such as logarithms, trigonometric and hyperbolic functions and their inverses. Here are a few examples to try:
from cmath import * z = 3 + 2j polar(z) abs(z) phase(z) log(z)See answers
polar(z) function converts z to polar form, which returns a tuple, with the first element being the amplitude of z and the second argument the phase. The
abs(z) function returns the amplitude (or absolute value) of z and
phase(z) returns the phase (in radians).
log(z) function returns the log (to base ). Since , applying the usual rules for the logarithm of a product and an exponential we get . We see from the answer above that log(3.605551275463989) = 1.2824746787307684, and the imaginary part is just j times the phase, as expected.
Readers familiar with complex variable theory will realize that the logarithm of a complex number is not unique. Since for any integer , we can in principle add any multiple of to the imaginary part of any logarithm. The log function in
cmath always returns a value with a phase in the range . If you want a different branch of the logarithm, you’ll need to account for it in the surrounding code.
Similar problems arise when calculating roots of complex numbers. If we calculate the square root of a positive real number, there are two possible answers, differing in the sign. In general, when calculating the th root of a complex number, there are different possible results. The answer returned by Python is the one obtained from taking the th root of the form of the complex number with the smallest phase. That is, if , then if we calculate
z ** (1/n), we get . Other roots would have to be calculated from this one.
Other functions of complex numbers have similar peculiarities, so you’ll need to be familiar with the mathematics if you want to use them properly. I don’t want to get too bogged down with details, but perhaps one more example might be useful.
To calculate the cosine of a complex number z we can use the formula . For , for example, this formula gives us
If you enter this formula into the Python console and compare the result with
cos(z), you’ll see that they are the same (well, up to the penultimate digit, anyway).
To get a complete list of functions in
cmath, in a fresh console type the commands:
import cmath help(cmath)
Write Python code to calculate the three cube roots (one real, two complex) of +1. Verify your answer by cubing the results and showing that they do indeed give +1.See answers
Code to calculate these three roots is:
from cmath import * z1 = 1 z2 = exp(2j * pi / 3) z3 = z2 * z2 # Verify the results z1 ** 3 z2 ** 3 z3 ** 3
When you calculated the cubes in the above exercise, you found that the answers were only approximately equal to +1 due to roundoff error. Try to find a way of expressing the cubes so that they give exactly +1.See answers
You can modify the code as follows:
from cmath import * z1 = 1 z2 = exp(2j * pi / 3) z3 = z2 * z2 # Verify the results z1cube = z1 ** 3 z2cube = z2 ** 3 z3cube = z3 ** 3 # Use the round() function on real & imaginary parts separately z1cube = round(z1cube.real) + round(z1cube.imag) * 1j z2cube = round(z2cube.real) + round(z2cube.imag) * 1j z3cube = round(z3cube.real) + round(z3cube.imag) * 1j