Simplify Complex Numbers With Python

Simplify Complex Numbers With Python

Most general-purpose programming languages have either no support or limited support for complex numbers. Your typical options are learning some specialized tool like MATLAB or finding a third-party library. Python is a rare exception because it comes with complex numbers built in.

Despite the name, complex numbers aren’t complicated! They’re convenient in tackling practical problems that you’ll get a taste of in this tutorial. You’ll explore vector graphics and sound frequency analysis, but complex numbers can also help in drawing fractals, such as the Mandelbrot set.

In this tutorial, you’ll learn how to:

  • Define complex numbers with literals in Python
  • Represent complex numbers in rectangular and polar coordinates
  • Use complex numbers in arithmetic expressions
  • Take advantage of the built-in cmath module
  • Translate mathematical formulas directly to Python code

If you need a quick refresher or a gentle introduction to the theory of complex numbers, then you can watch Khan Academy’s video series. To download the sample code used throughout this tutorial, click the link below:

Creating Complex Numbers in Python

Creating and manipulating complex numbers in Python isn’t much different from other built-in data types, particularly numeric types. It’s possible because the language treats them as first-class citizens. This means you can express mathematical formulas that involve complex numbers with little overhead.

Python lets you use complex numbers in arithmetic expressions and call functions on them just like you would with other numbers in Python. It leads to elegant syntax that reads almost like a math textbook.

Complex Number Literal

The quickest way to define a complex number in Python is by typing its literal directly in the source code:

Python
>>> z = 3 + 2j

Although this looks like an algebraic formula, the expression to the right of the equals sign is already a fixed value that needs no further evaluation. When you check its type, you’ll confirm that it’s indeed a complex number:

Python
>>> type(z)
<class 'complex'>

How is that different from adding two numbers with the plus operator? A clear giveaway is the letter j glued to the second number, which completely changes the meaning of the expression. If you removed the letter, you’d get a familiar integer result instead:

Python
>>> z = 3 + 2

>>> type(z)
<class 'int'>

By the way, you can use floating-point numbers to create complex numbers, too:

Python
>>> z = 3.14 + 2.71j
>>> type(z)
<class 'complex'>

Complex number literals in Python mimic the mathematical notation, which is also known as the standard form, the algebraic form, or sometimes the canonical form, of a complex number. In Python, you can use either lowercase j or uppercase J in those literals.

If you learned about complex numbers in math class, you might have seen them expressed using an i instead of a j. If you’re curious about why Python uses j instead of i, then you can expand the collapsible section below to learn more.

The traditional notation for complex numbers uses the letter i instead of j since it stands for the imaginary unit. You might feel a slight discomfort with Python’s convention if you have a mathematical background. However, there are a few reasons that can justify Python’s controversial choice:

  • It’s a convention already adopted by engineers to avoid name collisions with electric current, which is denoted with the letter i.
  • In computing, the letter i is often used for the indexing variable in loops.
  • The letter i can be easily confused with l or 1 in source code.

This was brought up on Python’s bug tracker over a decade ago, and Python’s creator, Guido van Rossum himself, closed the issue with this comment:

This will not be fixed. For one thing, the letter ‘i’ or upper case ‘I’ look too much like digits. The way numbers are parsed either by the language parser (in source code) or by the built-in functions (int, float, complex) should not be localizable or configurable in any way; that’s asking for huge disappointments down the road. If you want to parse complex numbers using ‘i’ instead of ‘j’, you have plenty of solutions available already. (Source)

So there you have it. Unless you want to start using MATLAB, you’ll have to live with using j to denote your complex numbers.

The algebraic form of a complex number follows the standard rules of algebra, which is convenient in performing arithmetic. For example, addition has a commutative property, which lets you swap the order of the two parts of a complex number literal without changing its value:

Python
>>> 3 + 2j == 2j + 3
True

Similarly, you can substitute addition for subtraction in a complex number literal because the minus sign is just a shorthand notation for an equivalent form:

Python
>>> 3 - 2j == 3 + (-2j)
True

Does a complex number literal in Python always have to comprise two numbers? Can it have more? Are they ordered? To answer these questions, let’s run some experiments. Unsurprisingly, if you specify only one number, without the letter j, then you’ll end up with a regular integer or a floating-point number:

Python
>>> z = 3.14
>>> type(z)
<class 'float'>

On the other hand, appending the letter j to a numeric literal will immediately turn it into a complex number:

Python
>>> z = 3.14j
>>> type(z)
<class 'complex'>

Strictly speaking, from a mathematical standpoint, you’ve just created a pure imaginary number, but Python can’t represent it as a stand-alone data type. Therefore, without the other part, it’s just a complex number .

How about the opposite? To create a complex number without the imaginary part, you can take advantage of zero and add or subtract it like so:

Python
>>> z = 3.14 + 0j
>>> type(z)
<class 'complex'>

In fact, both parts of the complex number are always there. When you don’t see one, it means that it has a value of zero. Let’s check what happens when you try stuffing more terms into the sum than before:

Python
>>> 2 + 3j + 4 + 5j
(6+8j)

This time, your expression is no longer a literal because Python evaluated it into a complex number comprising only two parts. Remember that the basic rules of algebra carry over to complex numbers, so if you group similar terms and apply component-wise addition, then you’ll end up with 6 + 8j.

Notice how Python displays complex numbers by default. Their textual representation contains an enclosing pair of parentheses, a lowercase letter j, and no whitespace. Additionally, the imaginary part comes second.

Complex numbers that also happen to be pure imaginary numbers show up without parentheses and only reveal their imaginary part:

Python
>>> 3 + 0j
(3+0j)
>>> 0 + 3j
3j

This helps differentiate imaginary numbers from most complex numbers made up of real and imaginary parts.

complex() Factory Function

Python has a built-in function, complex(), that you can use as an alternative to the complex number literal:

Python
>>> z = complex(3, 2)

In this form, it resembles a tuple or an ordered pair of ordinary numbers. The analogy isn’t that far-fetched. Complex numbers have a geometric interpretation in the Cartesian coordinate system that you’ll explore in a bit. You can think of complex numbers as two-dimensional.

The complex number factory function accepts two numeric parameters. The first one represents the real part, while the second one represents the imaginary part denoted with the letter j in the literal you saw earlier:

Python
>>> complex(3, 2) == 3 + 2j
True

Both parameters are optional, with default values of zero, which makes it less clunky to define complex numbers without the imaginary part or both the real and imaginary parts:

Python
>>> complex(3) == 3 + 0j
True
>>> complex() == 0 + 0j
True

The single-argument version can be useful in type casting. For example, you can pass a nonnumeric value like a string literal to obtain a corresponding complex object. Note that the string can’t contain any whitespace, though:

Python
>>> complex("3+2j")
(3+2j)

>>> complex("3 + 2j")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string

Later, you’ll find out how to make your classes compatible with this type casting mechanism. Interestingly, when you pass a complex number to complex(), you’ll get the same instance back:

Python
>>> z = complex(3, 2)
>>> z is complex(z)
True

That’s consistent with how other types of numbers in Python work because they’re all immutable. To make a distinct copy of a complex number, you must call the function with both arguments again or declare another variable with the complex number literal:

Python
>>> z = complex(3, 2)
>>> z is complex(3, 2)
False