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**, for example.

**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:

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:

```
>>> 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:

```
>>> z = 3 + 2
>>> type(z)
<class 'int'>
```

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

```
>>> 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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

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.

**Fun fact:** In math, complex numbers are traditionally denoted with the letter `z`

as it’s the next letter in the alphabet after `x`

and `y`

, which commonly represent coordinates.

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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

```
>>> 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:

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

When you provide two arguments to the function, they must always be numbers, such as `int`

, `float`

, or `complex`

. Otherwise, you’ll get a runtime error. Technically speaking, `bool`

is a subclass of `int`

, so it’ll work too:

```
>>> complex(False, True) # Booleans, same as complex(0, 1)
1j
>>> complex(3, 2) # Integers
(3+2j)
>>> complex(3.14, 2.71) # Floating-point numbers
(3.14+2.71j)
>>> complex("3", "2") # Strings
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: complex() can't take second arg if first is a string
```

Things get seemingly more bizarre when you supply the `complex()`

factory function with complex numbers as arguments. If you provide only the first argument, though, it’ll behave like a proxy as before:

```
>>> complex(complex(3, 2))
(3+2j)
```

However, when two arguments are present and at least one of them is a complex number, you’ll get results that may be difficult to explain at first sight:

```
>>> complex(1, complex(3, 2))
(-1+3j)
>>> complex(complex(3, 2), 1)
(3+3j)
>>> complex(complex(3, 2), complex(3, 2))
(1+5j)
```

To get the answers, let’s take a peek at the factory function’s docstring or the online documentation, which explain what’s going on under the hood when you call `complex(real, imag)`

:

Return a complex number with the value

real+imag*1j or convert a string or number to a complex number. (Source)

In this explanation, `real`

and `imag`

are names of the function arguments. The second argument gets multiplied by the imaginary unit `j`

, and the result is added to the first argument. Don’t worry if it still doesn’t make any sense. You can come back to this part when you’ve read about complex numbers arithmetic. The rules that you’ll learn about will make this straightforward.

When would you want to use the `complex()`

factory function over the literal? It depends, but calling the function may be more convenient when you’re dealing with dynamically generated data, for example.

## Getting to Know Python Complex Numbers

In mathematics, complex numbers are a superset of real numbers, which means that every real number is also a complex number whose imaginary part is equal to zero. Python models this relationship through a concept called the **numeric tower**, described in PEP 3141:

```
>>> import numbers
>>> issubclass(numbers.Real, numbers.Complex)
True
```

The built-in `numbers`

module defines a hierarchy of numeric types through **abstract classes** that can be used for type checking and classifying numbers. For example, to determine if a value belongs to a specific set of numbers, you can call `isinstance()`

on it:

```
>>> isinstance(3.14, numbers.Complex)
True
>>> isinstance(3.14, numbers.Integral)
False
```

The floating-point value `3.14`

is a real number that also happens to be a complex number but not an integral one. Note that you can’t use built-in types directly in such a test:

```
>>> isinstance(3.14, complex)
False
```

The difference between `complex`

and `numbers.Complex`

is that they belong to separate branches in the numeric type hierarchy tree, and the latter is an abstract base class without any implementation:

Abstract base classes, which are denoted in red on the diagram above, can bypass the regular inheritance check mechanism by registering unrelated classes as their virtual subclasses. That’s why a floating-point value in the example appears to be an instance of `numbers.Complex`

but not `complex`

.

### Accessing Real and Imaginary Parts

To get the real and imaginary parts of a complex number in Python, you can reach for the corresponding `.real`

and `.imag`

attributes:

```
>>> z = 3 + 2j
>>> z.real
3.0
>>> z.imag
2.0
```

Both properties are **read-only** because complex numbers are immutable, so trying to assign a new value to either of them will fail:

```
>>> z.real = 3.14
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
```

Since every number in Python is a more specific type of a complex number, attributes and methods defined in `numbers.Complex`

are also available in all numeric types, including `int`

and `float`

:

```
>>> x = 42
>>> x.real
42
>>> x.imag
0
```

The imaginary part of such numbers is always zero.

### Calculating the Conjugate of a Complex Number

Python complex numbers have only three public members. Apart from the `.real`

and `.imag`

properties, they expose the `.conjugate()`

method, which flips the sign of the imaginary part:

```
>>> z = 3 + 2j
>>> z.conjugate()
(3-2j)
```

For numbers whose imaginary part equals zero, it won’t have any effect:

```
>>> x = 3.14
>>> x.conjugate()
3.14
```

This operation is its own inverse, so calling it twice will get you the original number you started with:

```
>>> z.conjugate().conjugate() == z
True
```

While it may seem of little value, the complex conjugate has a few useful arithmetic properties that can help calculate the division of two complex numbers with pen and paper, among many other things.

## Complex Numbers Arithmetic

Since `complex`

is a native data type in Python, you can plug complex numbers into **arithmetic expressions** and call many of the built-in functions on them. More advanced functions for complex numbers are defined in the `cmath`

module, which is part of the standard library. You’ll get an introduction to it in a later part of this tutorial.

For now, remembering a single rule will let you apply your primary school knowledge of arithmetic to calculate basic operations involving complex numbers. The rule to remember is the definition of the **imaginary unit**, which satisfies the following equation:

It doesn’t look right when you think of `j`

as a real number, but don’t panic. If you ignore it for a moment and substitute every occurrence of `j`

^{2} with `-1`

as if it were a constant, then you’ll be set. Let’s see how that works.

### Addition

The sum of two or more complex numbers is equivalent to adding their real and imaginary parts component-wise:

```
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 + z2
(6+8j)
```

Earlier, you found out that algebraic expressions composed of real and imaginary numbers follow the standard rules of algebra. When you write it down algebraically, you’ll be able to apply the distributive property and simplify the formula by factoring out and grouping common terms:

Python automatically promotes operands to the `complex`

data type when you add values of mixed numeric types:

```
>>> z = 2 + 3j
>>> z + 7 # Add complex to integer
(9+3j)
```

That is similar to the implicit conversion from `int`

to `float`

, which you might be more familiar with.

### Subtraction

Subtracting complex numbers is analogous to adding them, which means you can also apply it element-wise:

```
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 - z2
(-2-2j)
```

Unlike the sum, however, the order of operands is significant and yields different results just like with real numbers:

```
>>> z1 + z2 == z2 + z1
True
>>> z1 - z2 == z2 - z1
False
```

You can also use the **unary minus operator (-)** to make the negative of a complex number:

```
>>> z = 3 + 2j
>>> -z
(-3-2j)
```

This inverts both the real and the imaginary parts of the complex number.

### Multiplication

The product of two or more complex numbers gets more interesting:

```
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 * z2
(-7+22j)
```

How on Earth did you end up with a *negative* number out of only positive ones? To answer this question, you have to recall the definition of the imaginary unit and rewrite the expression in terms of real and imaginary parts:

The key observation to make is that `j`

times `j`

gives `j`

^{2}, which can be replaced with `-1`

. This inverts the sign of one of the summands, while the rest of the rules stay exactly the same as before.

### Division

Dividing complex numbers can look intimidating at first encounter:

```
>>> z1 = 2 + 3j
>>> z2 = 4 + 5j
>>> z1 / z2
(0.5609756097560976+0.0487804878048781j)
```

Believe it or not, you’re able to get the same result using nothing more than a pen and paper! (Okay, a calculator might save you some headaches down the line.) When both numbers are expressed in their standard forms, the trick is to multiply the numerator and the denominator by the conjugate of the latter:

The denominator becomes a squared **modulus** of the divisor. You’ll learn more about the modulus of complex numbers later. When you continue deriving the formula, this is what you’ll get:

Note that complex numbers don’t support floor division, also known as integer division:

```
>>> z1 // z2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.
>>> z1 // 3.14
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.
```

This used to work in Python 2.x but was later removed to avoid ambiguity.

### Exponentiation

You can raise complex numbers to a power using the binary **exponentiation operator ( **)** or the built-in

`pow()`

but not the one defined in the `math`

module, which only supports floating-point values:```
>>> z = 3 + 2j
>>> z**2
(5+12j)
>>> pow(z, 2)
(5+12j)
>>> import math
>>> math.pow(z, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float
```

Both the **base** and the **exponent** can be of any numeric types, including integer, floating-point, imaginary, or complex:

```
>>> 2**z
(1.4676557979464138+7.86422192328995j)
>>> z**2
(5+12j)
>>> z**0.5
(1.8173540210239707+0.5502505227003375j)
>>> z**3j
(-0.13041489185767086-0.11115341486478239j)
>>> z**z
(-5.409738793917679-13.410442370412747j)
```

Manual exponentiation of complex numbers becomes very difficult when they’re expressed in their standard form. It’s much more convenient to rewrite the number in the **trigonometric form** and calculate the power using some basic trigonometry. If you’re interested in the math involved, check out De Moivre’s formula, which lets you do that.

## Using Python Complex Numbers as 2D Vectors

You can visualize complex numbers as **points** or **vectors** on a Euclidean plane in the Cartesian or **rectangular** coordinate system:

The X-axis on the complex plane, also known as the **Gauss plane** or **Argand diagram**, represents the real part of a complex number, while the Y-axis represents its imaginary part.

This fact leads to one of the coolest features of the `complex`

data type in Python, which embodies a rudimentary implementation of a two-dimensional vector for free. While not all operations work the same way in both of them, vectors and complex numbers share many similarities.

### Getting the Coordinates

The Bermuda Triangle is a legendary region known for its paranormal phenomena that spans across the southern tip of Florida, Puerto Rico, and the tiny island of Bermuda. Its vertices are approximately designated by the three major cities whose geographical coordinates are the following:

**Miami:**25° 45’ 42.054” N, 80° 11’ 30.438” W**San Juan:**18° 27’ 58.8” N, 66° 6’ 20.598” W**Hamilton:**32° 17’ 41.64” N, 64° 46’ 58.908” W

After converting these coordinates to decimal degrees, you’ll end up with two floating-point numbers for each city. You can use the `complex`

data type to store ordered pairs of numbers. Since the **latitude** is the vertical coordinate and the **longitude** is the horizontal one, it might be more convenient to switch them around to follow the traditional order of the Cartesian coordinates:

```
miami_fl = complex(-80.191788, 25.761681)
san_juan = complex(-66.105721, 18.466333)
hamilton = complex(-64.78303, 32.2949)
```

Negative longitude values represent the western hemisphere, while positive latitude values represent the northern hemisphere.

Bear in mind that these are **spherical coordinates**. To correctly project them onto a flat plane, you’d need to account for the curvature of Earth. One of the first map projections used in cartography was the Mercator projection, which helped sailors navigate their ships. But let’s ignore all that and assume that values are already expressed in the rectangular coordinate system.

When you plot the numbers on a complex plane, you’ll get a rough depiction of the Bermuda Triangle:

In the companion materials, you’ll find an interactive Jupyter Notebook that plots the Bermuda Triangle using the Matplotlib library. To download the source code and materials for this tutorial, click the link below:

If you don’t like calling the `complex()`

factory function, you can create a type alias with a better-suited name or use the literal form of a complex number to save a few keystrokes:

```
CityCoordinates = complex
miami_fl = CityCoordinates(-80.191788, 25.761681)
miami_fl = -80.191788 + 25.761681j
```

If you needed to pack more attributes on a city, you could use a named tuple or a data class or create a custom class.

### Calculating the Magnitude

The **magnitude**, also known as the **modulus** or **radius** of a complex number, is the length of the vector that depicts it on a complex plane:

You can calculate it from the Pythagorean theorem by taking the square root of the sum of the squared real part and the squared imaginary part:

You would think that Python would let you calculate the length of such a vector with the built-in `len()`

, but that’s not the case. To get the magnitude of a complex number, you have to call another global function named `abs()`

, which is typically used for calculating the **absolute value** of a number:

```
>>> len(3 + 2j)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'complex' has no len()
>>> abs(3 + 2j)
3.605551275463989
```

This function removes the sign from integers that you pass in, but for complex numbers, it returns the magnitude or vector length:

```
>>> abs(-42)
42
>>> z = 3 + 2j
>>> abs(z)
3.605551275463989
>>> from math import sqrt
>>> sqrt(z.real**2 + z.imag**2)
3.605551275463989
```

You might remember from an earlier section that a complex number multiplied by its conjugate produces its magnitude squared.

### Finding the Distance Between Two Points

Let’s find the Bermuda Triangle’s **geometric center** and the distances to it from the three cities that form its boundaries. First, you need to sum all coordinates and divide the result by their count to take the average:

```
geometric_center = sum([miami_fl, san_juan, hamilton]) / 3
```

This will give you a point located in the Atlantic Ocean, somewhere within the triangle:

Now you can create vectors anchored in the cities and directed toward the geometric center of the triangle. Vectors are made by subtracting the source from the target point:

```
v1 = geometric_center - miami_fl
v2 = geometric_center - san_juan
v3 = geometric_center - hamilton
```

Since you subtract complex numbers, every vector is also a complex number made up of two parts. To get your distances, calculate the magnitude of each vector:

```
>>> abs(v1)
9.83488994681275
>>> abs(v2)
8.226809506084367
>>> abs(v3)
8.784732429678444
```

These vector lengths don’t reflect meaningful distances but are good approximations for a toy example like this. To represent accurate results in tangible units, you’d have to convert the coordinates from spherical to rectangular first or calculate the distance using the great circle method instead.

### Translating, Flipping, Scaling, and Rotating

It might be bothering you that the triangle appears in the second quadrant of the Cartesian coordinate system. Let’s move it so that its geometric center aligns with the origin. All three vertices will be **translated** by the length of the vector indicated by the geometric center but in the opposite direction:

```
triangle = miami_fl, san_juan, hamilton
offset = -geometric_center
centered_triangle = [vertex + offset for vertex in triangle]
```

Note that you’re adding two complex numbers together, which performs their element-wise addition. This is an affine transformation since it doesn’t change the shape of the triangle or the relative placement of its vertices:

A mirror reflection of the triangle around the real or imaginary axis requires inverting the respective component in its vertices. For example, to **flip** it horizontally, you’ll have to use the negative of the real part, which corresponds to the horizontal direction. To flip it vertically, you’ll take the negative of the imaginary part:

```
flipped_horizontally = [complex(-v.real, v.imag) for v in centered_triangle]
flipped_vertically = [complex(v.real, -v.imag) for v in centered_triangle]
```

The latter is essentially the same as calculating a complex number conjugate, so you can call `.conjugate()`

on each vertex directly to do the hard work for you:

```
flipped_vertically = [v.conjugate() for v in centered_triangle]
```

Naturally, there’s nothing to stop you from applying the symmetry in either direction or both directions simultaneously. In such a case, you can use the unary minus operator in front of the complex number to flip its real and imaginary parts:

```
flipped_in_both_directions = [-v for v in centered_triangle]
```

Go ahead and fiddle with the different flip combinations using the interactive Jupyter Notebook available in the downloadable materials. Here’s how the triangle will look when you flip it along both axes:

**Scaling** is similar to translating, but instead of adding an offset, you’re going to multiply each vertex by a constant factor, which must be a *real* number:

```
scaled_triangle = [1.5*vertex for vertex in centered_triangle]
```

Doing so results in multiplying both components of each complex number by the same amount. It should stretch your Bermuda Triangle, making it look bigger on the plot:

Multiplying the triangle’s vertices by another *complex* number, on the other hand, has the effect of **rotating** it around the coordinate system’s origin. That’s vastly different from how you’d typically multiply vectors by each other. For example, a dot product of two vectors will result in a scalar, while their cross product returns a new vector in three-dimensional space, which is perpendicular to the surface they define.

**Note:** The product of two complex numbers doesn’t represent vector multiplication. Instead, it’s defined as **matrix multiplication** in a two-dimensional vector space, with 1 and `j`

as the standard basis. Multiplying (*x*_{1} + *y*_{1}`j`

) by (*x*_{2} + *y*_{2}`j`

) corresponds to the following matrix multiplication:

This is the **rotation matrix** on the left, which makes the math work out just fine.

When you multiply the vertices by the imaginary unit, it will rotate the triangle 90° counterclockwise. If you keep repeating it, you’ll eventually arrive where you started:

How do you find a specific complex number that will rotate another complex number by any desired angle when both are multiplied? First, take a look at the following table, which summarizes the consecutive rotations by 90°:

90° rotations | Total angle | Formula | Exponent | Value |
---|---|---|---|---|

0 | 0° | z |
`j` ^{0} |
1 |

1 | 90° | z × `j` |
`j` ^{1} |
`j` |

2 | 180° | z × `j` × `j` |
`j` ^{2} |
-1 |

3 | 270° | z × `j` × `j` × `j` |
`j` ^{3} |
–`j` |

4 | 360° | z × `j` × `j` × `j` × `j` |
`j` ^{4} |
1 |

5 | 450° | z × `j` × `j` × `j` × `j` × `j` |
`j` ^{5} |
`j` |

6 | 540° | z × `j` × `j` × `j` × `j` × `j` × `j` |
`j` ^{6} |
-1 |

7 | 630° | z × `j` × `j` × `j` × `j` × `j` × `j` × `j` |
`j` ^{7} |
–`j` |

8 | 720° | z × `j` × `j` × `j` × `j` × `j` × `j` × `j` × `j` |
`j` ^{8} |
1 |

When you express the repeated multiplication by `j`

in terms of positive integer exponents, then a pattern emerges. Notice how raising the imaginary unit to the subsequent powers makes it cycle through the same values repeatedly. You can extrapolate this onto fractional exponents and expect them to correspond to the intermediate angles.

For example, the exponent halfway through the first rotation is equal to 0.5 and represents a 45° angle:

So, if you know that a power of one represents the right angle, and anything in between scales proportionally, then you can derive this generic formula for arbitrary rotations:

```
def rotate(z: complex, degrees: float) -> complex:
return z * 1j**(degrees/90)
```

Note that rotation becomes more natural when you express your complex numbers in polar coordinates, which already describe the angle. You can then take advantage of the **exponential form** to make the calculations more straightforward:

There are two ways to rotate a number using polar coordinates:

```
import math, cmath
def rotate1(z: complex, degrees: float) -> complex:
radius, angle = cmath.polar(z)
return cmath.rect(radius, angle + math.radians(degrees))
def rotate2(z: complex, degrees: float) -> complex:
return z * cmath.rect(1, math.radians(degrees))
```

You can sum angles or multiply your complex number by a unit vector.

You’ll learn more about those in the next section.

## Exploring the Math Module for Complex Numbers: `cmath`

You’ve already seen that some built-in functions like `abs()`

and `pow()`

accept complex numbers, while others don’t. For example, you can’t `round()`

a complex number because such an operation doesn’t make sense:

```
>>> round(3 + 2j)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type complex doesn't define __round__ method
```

Many advanced mathematical functions such as **trigonometric**, **hyperbolic**, or **logarithmic** functions are available in the standard library. Sadly, even if you know everything about the Python `math`

module, it won’t help because none of its functions support complex numbers. You’ll need to combine it with the `cmath`

module, which defines corresponding functions for complex numbers.

The `cmath`

module redefines all floating-point constants from `math`

so that they’re at your fingertips without the need to import both modules:

```
>>> import math, cmath
>>> for name in "e", "pi", "tau", "nan", "inf":
... print(name, getattr(math, name) == getattr(cmath, name))
...
e True
pi True
tau True
nan False
inf True
```

Note that `nan`

is a special value which is never equal to anything else, including itself! That’s why you’re seeing a solitary `False`

in the output above. In addition to these, `cmath`

provides two complex counterparts for NaN (not a number) and infinity, with both having zero real parts:

```
>>> from cmath import nanj, infj
>>> nanj.real, nanj.imag
(0.0, nan)
>>> infj.real, infj.imag
(0.0, inf)
```

There are about half as many functions in `cmath`

as there are in the standard `math`

module. Most of them mimic the original behavior, but a few are unique to complex numbers. They will let you do the conversion between two coordinate systems that you’ll explore in this section.

### Converting Between Rectangular and Polar Coordinates

Geometrically, you can look at a complex number twofold. On the one hand, it’s a point whose horizontal and vertical distances from the origin uniquely identify its location. These are known as **rectangular coordinates** comprising the real and imaginary parts.

On the other hand, you can describe the same point in **polar coordinates** that also let you find it unambiguously with two distances:

**Radial distance**is the length of the radius measured from the origin.**Angular distance**is the angle measured between the horizontal axis and the radius.

The **radius**, also known as the **modulus**, corresponds to the complex number’s magnitude, or the vector’s length. The angle is commonly referred to as the **phase** or **argument** of a complex number. It’s useful to express the angle in radians rather than degrees when working with trigonometric functions.

Here’s a depiction of a complex number in both coordinate systems:

Therefore, a point (3, 2) in the Cartesian coordinate system has a radius of approximately 3.6 and an angle of about 33.7°, or roughly π over 5.4 radians.

The conversion between the two coordinate systems is made possible with a couple of functions buried in the `cmath`

module. Specifically, to get the polar coordinates of a complex number, you must pass it to `cmath.polar()`

:

```
>>> import cmath
>>> cmath.polar(3 + 2j)
(3.605551275463989, 0.5880026035475675)
```

It will return a tuple, where the first element is the radius and the second element is the angle in radians. Note that the radius has the same value as the magnitude, which you can calculate by calling `abs()`

on your complex number. Conversely, if you were only interested in getting the angle of a complex number, then you could call `cmath.phase()`

:

```
>>> z = 3 + 2j
>>> abs(z) # Magnitude is also the radial distance
3.605551275463989
>>> import cmath
>>> cmath.phase(3 + 2j)
0.5880026035475675
>>> cmath.polar(z) == (abs(z), cmath.phase(z))
True
```

The angle can be obtained using basic trigonometry since the real part, the imaginary part, and the magnitude together form a right triangle:

You can use the inverse trigonometric functions, such as **arcsine**, either from `math`

or `cmath`

, but the latter will produce complex values with the imaginary part equal to zero:

```
>>> z = 3 + 2j
>>> import math
>>> math.acos(z.real / abs(z))
0.5880026035475675
>>> math.asin(z.imag / abs(z))
0.5880026035475676
>>> math.atan(z.imag / z.real) # Prefer math.atan2(z.imag, z.real)
0.5880026035475675
>>> import cmath
>>> cmath.acos(z.real / abs(z))
(0.5880026035475675-0j)
```

There’s one small detail to be careful about when using the **arctangent** function, though, which led many programming languages to develop an alternative implementation called `atan2()`

. Calculating the ratio between the imaginary and the real part can sometimes produce a singularity due to, for instance, division by zero. Moreover, the individual signs of the two values are lost in the process, making it impossible to tell the angle with certainty:

```
>>> import math
>>> math.atan(1 / 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> math.atan2(1, 0)
1.5707963267948966
>>> math.atan(1 / 1) == math.atan(-1 / -1)
True
>>> math.atan2(1, 1) == math.atan2(-1, -1)
False
```

Notice how `atan()`

fails to recognize two different points located in the opposite quadrants of the coordinate system. On the other hand, `atan2()`

expects two arguments instead of one to preserve the individual signs before dividing one by another and avoids other problems as well.

To get degrees instead of radians, you can make the necessary conversion using the `math`

module again:

```
>>> import math
>>> math.degrees(0.5880026035475675) # Radians to degrees
33.690067525979785
>>> math.radians(180) # Degrees to radians
3.141592653589793
```

Reversing the process—that is, converting polar to rectangular coordinates—relies on another function. However, you can’t just pass the same tuple that you got from `cmath.polar()`

since `cmath.rect()`

expects two separate arguments:

```
>>> cmath.rect(cmath.polar(3 + 2j))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: rect expected 2 arguments, got 1
```

It’s a good idea to unpack the tuple first when doing an assignment and give those elements more descriptive names. Now you can call `cmath.rect()`

correctly:

```
>>> radius, angle = cmath.polar(3 + 2j)
>>> cmath.rect(radius, angle)
(3+1.9999999999999996j)
```

You might encounter rounding errors along the way while Python makes the calculations. Behind the scenes, it calls the trigonometric functions to retrieve the real and imaginary parts:

```
>>> import math
>>> radius*(math.cos(angle) + math.sin(angle)*1j)
(3+1.9999999999999996j)
>>> import cmath
>>> radius*(cmath.cos(angle) + cmath.sin(angle)*1j)
(3+1.9999999999999996j)
```

Again, it doesn’t matter whether you use `math`

or `cmath`

in this case as the results will be identical.

### Representing Complex Numbers Differently

Regardless of the coordinate system, you can express the same complex number in a few mathematically equivalent forms:

- Algebraic (standard)
- Geometric
- Trigonometric
- Exponential

This list isn’t exhaustive as there are more representations, such as the matrix representation of complex numbers.

Having the choice lets you pick the most convenient one to tackle a given problem. For example, you’re going to need the exponential form to calculate discrete Fourier transform in an upcoming section. Using this form is also suitable for multiplying and dividing complex numbers.

Here’s a quick rundown of the individual complex number forms and their coordinates:

Form | Rectangular | Polar |
---|---|---|

Algebraic | z = x + y`j` |
– |

Geometric | z = (x, y) |
z = (r, φ) |

Trigonometric | z = |z|(cos(x/|z|) + `j` sin(y/|z|)) |
z = r(cos(φ) + `j` sin(φ)) |

Exponential | z = |z|e^{atan2(y/x)j} |
z = r(e^{jφ}) |

The algebraic form is native to Python when you specify complex numbers using their literals. You can also view them as points on a Euclidean plane in the Cartesian or polar coordinate systems. While there aren’t separate representations for the trigonometric or exponential form in Python, you can verify if mathematical principles hold.

For example, plugging in Euler’s formula to the trigonometric form will turn it into the exponential one. You can either call the `cmath`

module’s `exp()`

or raise the `e`

constant to a power to get the same result:

```
>>> import cmath
>>> algebraic = 3 + 2j
>>> geometric = complex(3, 2)
>>> radius, angle = cmath.polar(algebraic)
>>> trigonometric = radius * (cmath.cos(angle) + 1j*cmath.sin(angle))
>>> exponential = radius * cmath.exp(1j*angle)
>>> for number in algebraic, geometric, trigonometric, exponential:
... print(format(number, "g"))
...
3+2j
3+2j
3+2j
3+2j
```

All forms are indeed different ways of encoding the same number. However, you can’t compare them directly because of the rounding errors that may occur in the meantime. Use `cmath.isclose()`

for a safe comparison or `format()`

the numbers as strings appropriately. You’ll find out how to format such strings in the upcoming section.

The explanation of why different forms of a complex number are equivalent requires calculus and goes far beyond the scope of this tutorial. However, if you’re interested in math, then you’ll find the connections between different fields of mathematics that are exhibited by complex numbers to be fascinating.

## Dissecting a Complex Number in Python

You’ve already learned a bunch about Python complex numbers and have seen preliminary examples. However, before moving further, it’s worthwhile to cover some final topics. In this section, you’re going to look into comparing complex numbers, formatting strings that contain them, and more.

### Testing Equality of Complex Numbers

Mathematically, two complex numbers are equal when they have identical values irrespective of the adopted coordinate system. However, converting between polar and rectangular coordinates typically introduces rounding errors in Python, so you need to watch out for minute differences when comparing them.

For example, when you consider a point on a unit circle whose radius is equal to one and is tilted at 60°, then the trigonometry works out nicely, making the conversion with pen and paper straightforward:

```
>>> import math, cmath
>>> z1 = cmath.rect(1, math.radians(60))
>>> z2 = complex(0.5, math.sqrt(3)/2)
>>> z1 == z2
False
>>> z1.real, z2.real
(0.5000000000000001, 0.5)
>>> z1.imag, z2.imag
(0.8660254037844386, 0.8660254037844386)
```

Even though you know that `z1`

and `z2`

are the same point, Python can’t determine that because of the rounding errors. Fortunately, the PEP 485 document defined functions for approximate equality, which are available in the `math`

and `cmath`

modules:

```
>>> math.isclose(z1.real, z2.real)
True
>>> cmath.isclose(z1, z2)
True
```

Remember to always use them when comparing complex numbers! If the default tolerance isn’t good enough for your calculations, you can change it by specifying additional arguments.

### Ordering Complex Numbers

If you’re familiar with tuples, then you know that Python can sort them:

```
>>> planets = [
... (6, "saturn"),
... (4, "mars"),
... (1, "mercury"),
... (5, "jupiter"),
... (8, "neptune"),
... (3, "earth"),
... (7, "uranus"),
... (2, "venus"),
... ]
>>> from pprint import pprint
>>> pprint(sorted(planets))
[(1, 'mercury'),
(2, 'venus'),
(3, 'earth'),
(4, 'mars'),
(5, 'jupiter'),
(6, 'saturn'),
(7, 'uranus'),
(8, 'neptune')]
```

By default, the individual tuples are compared left to right:

```
>>> (6, "saturn") < (4, "mars")
False
>>> (3, "earth") < (3, "moon")
True
```

In the first case, the number `6`

is greater than `4`

, so the planet names aren’t considered at all. They can help resolve a tie, though. However, that’s not the case with complex numbers since they *don’t* define a natural ordering relation. For example, you’ll get an error if you try to compare two complex numbers:

```
>>> (3 + 2j) < (2 + 3j)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'
```

Should the imaginary dimension have more weight than the real one? Should their magnitudes be compared? It’s up to you, and the answers will vary. Since you can’t compare complex numbers directly, you need to tell Python how to sort them by specifying a custom **key function**, such as `abs()`

:

```
>>> cities = {
... complex(-64.78303, 32.2949): "Hamilton",
... complex(-66.105721, 18.466333): "San Juan",
... complex(-80.191788, 25.761681): "Miami"
... }
>>> for city in sorted(cities, key=abs, reverse=True):
... print(abs(city), cities[city])
...
84.22818453809096 Miami
72.38647347392259 Hamilton
68.63651945864338 San Juan
```

This will sort the complex numbers by their magnitude in descending order.

### Formatting Complex Numbers as Strings

There aren’t any format codes specific to complex numbers, but you can format their real and imaginary parts separately using standard codes for floating-point numbers. Below, you’ll find a few techniques that demonstrate this. Some of them will actually apply your format specifier to both the real and imaginary parts in one go.

**Note:** String formatting can let you ignore the floating-point representation error and pretend it doesn’t exist:

```
>>> import cmath
>>> z = abs(3 + 2j) * cmath.exp(1j*cmath.phase(3 + 2j))
>>> str(z)
'(3+1.9999999999999996j)'
>>> format(z, "g")
'3+2j'
```

The letter `"g"`

in the format specifier stands for **general format**, which rounds your number to the requested precision. The default precision is six significant figures.

Let’s take the following complex number as an example and format it with two decimal places on both parts:

```
>>> z = pow(3 + 2j, 0.5)
>>> print(z)
(1.8173540210239707+0.5502505227003375j)
```

A quick way to do this is either by calling `format()`

with a numeric format specifier or by creating an appropriately formatted f-string:

```
>>> format(z, ".2f")
'1.82+0.55j'
>>> f"{z:.2f}"
'1.82+0.55j'
```

If you want more control, for example, to add extra padding around the plus operator, then the f-string will be a better choice:

```
>>> f"{z.real:.2f} + {z.imag:.2f}j"
'1.82 + 0.55j'
```

You can also call `.format()`

on a string object and pass **positional** or **keyword arguments** to it:

```
>>> "{0:.2f} + {0:.2f}j".format(z.real, z.imag)
'1.82 + 1.82j'
>>> "{re:.2f} + {im:.2f}j".format(re=z.real, im=z.imag)
'1.82 + 0.55j'
```

The positional arguments provide a sequence of values, while the keyword arguments let you refer to them by name. Similarly, you can use the string modulo operator (`%`

) with either a tuple or a dictionary:

```
>>> "%.2f + %.2fj" % (z.real, z.imag)
'1.82 + 0.55j'
>>> "%(re).2f + %(im).2fj" % {"re": z.real, "im": z.imag}
'1.82 + 0.55j'
```

However, this uses a different placeholder syntax and is slightly old-fashioned.

### Creating Your Own Complex Data Type

The Python data model defines a set of special methods that you can implement to make your classes compatible with certain built-in types. Say you were working with points and vectors and wanted to get the angle between two **bound vectors**. You might calculate their dot product and do some trigonometry. Alternatively, you can take advantage of complex numbers.

Let’s define your classes first:

```
from typing import NamedTuple
class Point(NamedTuple):
x: float
y: float
class Vector(NamedTuple):
start: Point
end: Point
```

A `Point`

has the `x`

and `y`

coordinates, while a `Vector`

connects two points. You might remember `cmath.phase()`

, which calculates the angular distance of a complex number. Now, if you treated your vectors as complex numbers and knew their phases, then you could subtract them to obtain the desired angle.

To make Python recognize vector instances as complex numbers, you have to supply `.__complex__()`

in the class body:

```
class Vector(NamedTuple):
start: Point
end: Point
def __complex__(self):
real = self.end.x - self.start.x
imag = self.end.y - self.start.y
return complex(real, imag)
```

The code inside must always return an instance of the `complex`

data type, so it typically constructs a new complex number out of your object. Here, you’re subtracting the initial and terminal points to get the horizontal and vertical displacements, which serve as the real and imaginary parts. The method will run through **delegation** when you call the global `complex()`

on a vector instance:

```
>>> vector = Vector(Point(-2, -1), Point(1, 1))
>>> complex(vector)
(3+2j)
```

In some cases, you don’t have to make this kind of type casting yourself. Let’s see an example in practice:

```
>>> v1 = Vector(Point(-2, -1), Point(1, 1))
>>> v2 = Vector(Point(10, -4), Point(8, -1))
>>> import math, cmath
>>> math.degrees(cmath.phase(v2) - cmath.phase(v1))
90.0
```

You’ve got two vectors identified by four distinct points. Next, you pass them directly to `cmath.phase()`

, which does the conversion to a complex number for you and returns the phase. The phase difference is the angle between the two vectors.

Wasn’t that beautiful? You’ve saved yourself from typing a lot of error-prone code by piggybacking on the complex numbers and a bit of Python magic.

## Calculating the Discrete Fourier Transform With Complex Numbers

While you can use real numbers to calculate the sine and cosine coefficients of a periodic function’s frequencies with the Fourier transform, it’s usually more convenient to deal with only one complex coefficient per frequency. The **discrete Fourier transform** in the complex domain is given by the following formula:

For each **frequency bin** *k*, it measures the correlation of the signal and a particular sine wave expressed as a complex number in the exponential form. (Thank you, Leonhard Euler!) The angular frequency of the wave can be calculated by multiplying the round angle, which is 2π radians, by *k* over the number of discrete samples:

Coding this in Python looks quite neat when you take advantage of the `complex`

data type:

```
from cmath import pi, exp
def discrete_fourier_transform(x, k):
omega = 2 * pi * k / (N := len(x))
return sum(x[n] * exp(-1j * omega * n) for n in range(N))
```

This function is a literal transcription of the formulas above. Now you can run a frequency analysis on a sound that you load from an audio file using Python’s `wave`

module or that you synthesize from scratch. One of the Jupyter Notebooks accompanying this tutorial lets you play with audio synthesis and analysis interactively.

To plot the **frequency spectrum** with Matplotlib, you must know the sampling frequency, which determines your **frequency bin resolution** as well as the Nyquist limit:

```
import matplotlib.pyplot as plt
def plot_frequency_spectrum(
samples,
samples_per_second,
min_frequency=0,
max_frequency=None,
):
num_bins = len(samples) // 2
nyquist_frequency = samples_per_second // 2
magnitudes = []
for k in range(num_bins):
magnitudes.append(abs(discrete_fourier_transform(samples, k)))
# Normalize magnitudes
magnitudes = [m / max(magnitudes) for m in magnitudes]
# Calculate frequency bins
bin_resolution = samples_per_second / len(samples)
frequency_bins = [k * bin_resolution for k in range(num_bins)]
plt.xlim(min_frequency, max_frequency or nyquist_frequency)
plt.bar(frequency_bins, magnitudes, width=bin_resolution)
```

The number of frequency bins in the spectrum is equal to half the samples, while the Nyquist frequency limits the highest frequency you can measure. The transform returns a complex number whose magnitude corresponds to the **amplitude** of a sine wave at the given frequency, whereas its angle is the **phase**.

**Note:** To get correct amplitude values, you must double the number and divide the resulting magnitude by the sample count. On the other hand, if you only care about a frequency histogram, then you can normalize magnitudes by their sum or the maximum frequency.

Here’s a sample frequency plot of a sound wave comprising three tones—440 Hz, 1.5 kHz, and 5 kHz—having equal amplitudes:

Note this was a purely academic example since calculating the discrete Fourier transform with nested iterations has *O*(*n*^{2}) time complexity, making it unusable in practice. For real-life applications, you want to use the **fast Fourier transform (FFT)** algorithm best implemented in a C library, such as the FFT in SciPy.

## Conclusion

The ease of using complex numbers in Python makes them a surprisingly fun and practical tool. You saw two-dimensional **vectors** implemented practically for free, and you were able to analyze **sound frequencies** thanks to them. Complex numbers let you elegantly express **mathematical formulas** in code without much boilerplate syntax standing in the way.

**In this tutorial, you learned 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

What has your experience been with Python complex numbers so far? Were you ever intimidated by them? What other interesting problems do you think they’ll let you solve?

You can click the link below to get the full source code for this tutorial: