Complex Numbers in Python


Complex numbers are the sums and differences of real and imaginary numbers. In order to work with complex numbers, we must first understand imaginary numbers. Real numbers are the numbers that we are most familiar with such as: 1, 0.67, -5, etc. The square root of any real number has two roots, a positive and a negative. That's why when we solve for the square root of the real number, 25, we get a result of +/- 5.

This is not the case with imaginary numbers. When attempting to solve for the square root of i (an imaginary number) it will always evaluate to -1. In other words, i * i = -1. It is impossible to get an answer of -1 when solving the square root of a real number. So, you may be wondering where complex numbers come into play.

It's not possible to combine real and imaginary numbers, thus when attempting to do so, we are creating a complex number. In the example below, g is a complex number, 6 is a real number, and i is an imaginary number multiplied by 2.

g = 6 + 2i

Note

So far, we have only represented imaginary numbers using the variable, i, to make it easier to recognize which value is imaginary. Though, imaginary numbers can be defined with any variable.

Now that we have a basic understanding of complex numbers, let's take a look at how they can be used in a programming language like Python.

Creating Complex Numbers

Python has built-in tools that make it easy to work with real, imaginary, and complex numbers. To utilize python's complex datatype, we just need to create a complex number, like so:

>>> x = 4 + 6j
>>> type(x)
<class 'complex'>

Real, Imaginary, and Conjugate Attributes

Checking the type of x, python confirms that it is a complex number. The complex datatype has built-in attributes that recognize real and imaginary numbers as well. We can check for those by calling their respective attributes.

>>> x.real
4.0
>>> x.imag
6.0
>>> x.conjugate()
(4-6j)

As seen above, python will return the real number from the complex number, x by simply using .real. Finding imaginary numbers works similarly except that "imaginary" is shortened to .imag. The last input gives us the conjugate of the complex number, x.

Our imaginary number from the last example resulted in 6.0 because the imaginary number j had a leading number of 6. In general, if there is no number in front of j, then it is implied that the leading coefficient of the imaginary number is 1. However, in python, you must explicitly define it:

>>> z = 4 + i
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'i' is not defined
>>> z = 4 + 1i
>>> z.imag
1.0

Why Do We Need Complex Numbers in Programming?

You may be wondering when (or if) complex numbers will ever come in handy. In certain fields, particularly science and engineering, professionals use complex numbers far more frequently than a web developer. For instance, as an electrical engineer, you may need to use real numbers to demonstrate electrical resistance and complex numbers to indicate electrical reactance.

Complex numbers are unlikely to be used in many web apps, but there are a number of professional uses for them. Since Python is the programming language-of-choice for machine learning, data science, as well as other scientific and academic applications, it's safe to say that complex numbers are a helpful feature to have built-in.

With that being said, you would probably like to begin working with more advanced problems that could be deemed useful in the future.

Mathematical Calculations

Although they seem basic in rectrospect, simple calculations prove to be an important use of complex numbers in scientific applications. Let's see these calculations in action:

# Definition of complex numbers
>>> c1 = 7 + 2j
>>> c2 = 5 + 14j

# Addition
>>> print(c1 + c2)
(12+16j)

# Subtraction
>>> print(c1 - c2)
(2-12j)

# Multiplication
>>> print(c1 * c2)
(7+108j)

# Division
>>> print(c1 / c2)
(0.2850678733031674-0.39819004524886875j)

The addition and subtraction equations are obvious enough to solve in our heads, but the multiplication and division problems are another story. The terminal takes in the input and spits out an answer in a flash, but how does the program come to this result?

    (c1 * c2) =
    (7 + 2j)(5 + 14j) =
    35 + 98j + 10j + 28j^2 =
    35 - 28 + 108j =
    7 + 108j

In the multiplication problem, we multiply each of the terms together and then combine like terms. 28j^2 is equal to -28 because an imaginary number raised to the second power is equal to -1. This leads us to the same result as we saw on the command line.

Division is a tad trickier than multiplication. Remember the conjugate attribute that we saw earlier? It may have seemed like an unnecessary operation at first, but it will allow us to divide complex numbers.

    (c1 / c2) =
    (7 + 2j) / (5 + 14j) =
    ((7 + 2j) * (5 - 14j)) / ((5 + 14j) * (5 - 14j)) =
    (35 - 98j + 10j - 28j^2) / (25 - 70j + 70j - 196j^2) =
    (35 - 88j + 28) / (25 + 196) =
    (63 - 88j) / 221 =
    ------------------
    63 / 221 = 0.285
    -88 / 221 = 0.398
    ------------------
    0.285 - 0.398j

Starting from the top, we begin by multiplying, both, c1 (7 + 2j) and c2 (5 + 14j) by the divisor's conjugate. In this case, we're dividing by c2, so the conjugate is (5 - 14j). The next step is to combine like terms until we have the simplest form.

In the above example, we can simplify the equation to (63 - 88j) / 221. At this point, we're finally able to begin dividing. We divide the divisor, 221, by the real number as well as the leading coefficient of the imaginary number, 63 and -88. Although the result is rounded to the nearest thousandth place, we have still found the same result as the command line.

Performing Operations With cmath

Now that you should have a better understanding of the logic behind the complex number functions in python. The cmath module is very similar to Python's math module, except that it's made for complex numbers. Even if a real number is passed into these functions, it will return a complex result.

Power and Log Functions

This section assumes that you have knowledge of how exponents and logs work, if not then it may be best to review these concepts first.

In this example, you'll notice that we start off by importing the cmath module and then defining our complex number, c. The next thing we do is plug c into cmath's exp attribute. As you've probably guessed, this is shortened for "exponential" as it's solving for e^c. In other words, you're solving for Euler's number raised to the complex number argument, in our case c describes our complex number.

The next two functions find the log of c, but with different base values: 2 and 10. Lastly, sqrt finds the square root of the given argument.

>>> import cmath
>>> c = 5 + 12j
>>> cmath.exp(c)
(125.23903183670447-79.63448184933233j)
>>> cmath.log(c, 2)
(3.700439718141092+1.6966168803357498j)
>>> cmath.log10(c)
(1.1139433523068367+0.510732572130908j)
>>> cmath.sqrt(c)
(3+2j)

Simple functions like these make working with complex numbers much easier.

Trigonometric Functions

The cmath module also has trigonometric functions built-in as well. Which makes solving for sine, cosine, tangent, and their hyperbolic equivalents a breeze. Below you'll see an example of these functions in use. If you don't feel comfortable with these functions, then it's advisable to brush up on their basics before using these in your code. Otherwise, these should be pretty familiar.

>>> cmath.asinh(c)
(3.2570549430613376+1.17495153383925j)
>>> cmath.acosh(c)
(3.2591381880008243+1.1770523156860924j)
>>> cmath.atanh(c)
(0.029445758914095864+1.4998477994928145j)
>>> cmath.sin(c)
(-78034.76015765528+23083.689913391663j)
>>> cmath.cos(c)
(23083.689915134542+78034.76015176345j)
>>> cmath.tan(c)
(-4.1075057773313194e-11+1.0000000000633522j)

Takeaway

Complex numbers are a bit unusual. They're composed of real and imaginary numbers and are not necessarily the simplest to work with. Using the functions and attributes that we've reviewed thus far will aid in building programs that can be used for a variety of science and engineering applications. If some of these functions seem difficult to understand, it's best to research the basic logic behind them. Once they're understood, they're very simple and easy-to-use for just about anyone.

With this article at OpenGenus, you must have a complete idea of Complex Numbers in Python. Enjoy.