Skip to Content
Course content

236: The <complex> Header for Complex Numbers

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I remember the first time I tried to implement a basic Fourier transform. I thought I'd be clever and keep my coordinates as integers to avoid floating-point drift in a specific part of my logic. I reached for the <complex> header, figured I'd just instantiate it with an int, and then I spent twenty minutes staring at a compiler error that looked like a novel.

#include <iostream>
#include <complex>

int main() {
    // Trying to use integers for a simple grid-based complex coordinate
    std::complex<int> point(3, 4); 
    std::cout << "Point: " << point << std::endl;
    return 0;
}

The Template Type Trap

If you try to compile the code above, your compiler is going to scream at you. You'll see a wall of text mentioning that std::complex<int> doesn't satisfy the requirements of the template. Here is the deal: the C++ standard explicitly restricts std::complex to floating-point types. Specifically, it only works with float, double, and long double.

Why? Because complex number math—especially things like square roots, norms, and polar coordinates—almost always results in non-integer values. The library designers decided not to allow integers to prevent you from accidentally truncating your data and wondering why your physics simulation is behaving like a glitchy 1980s arcade game.

The fix is simple: use double. Even if your inputs are whole numbers, the container must be floating-point.

#include <iostream>
#include <complex>

int main() {
    // Use double, even if the numbers are whole
    std::complex<double> point(3.0, 4.0); 
    std::cout << "Point: " << point << std::endl;
    return 0;
}

Moving Beyond Real and Imaginary

Once you've got the type right, don't fall into the trap of manually calculating magnitudes or phases using sqrt(r*r + i*i). I've seen too many junior devs do this. The <complex> header provides overloaded versions of standard math functions that are more efficient and numerically stable.

You have access to:

  • std::abs(z): Calculates the magnitude (the distance from the origin).
  • std::arg(z): Returns the phase angle (argument) in radians.
  • std::norm(z): Returns the squared magnitude (useful because it avoids a costly square root).
  • std::conj(z): Returns the complex conjugate.

I usually prefer std::norm when I'm just comparing distances between two complex points, because calculating a square root is expensive for the CPU. If you don't need the actual distance, don't pay the performance tax for it.

#include <iostream>
#include <complex>
#include <cmath>

int main() {
    std::complex<double> z(3.0, 4.0);

    std::cout << "Magnitude: " << std::abs(z) << "\n"; // 5.0
    std::cout << "Phase: " << std::arg(z) << " rad\n";
    std::cout << "Squared Norm: " << std::norm(z) << "\n"; // 25.0
    
    // Accessing parts specifically
    std::cout << "Real part: " << z.real() << "\n";
    std::cout << "Imag part: " << z.imag() << "\n";

    return 0;
}

One last tip: you can use the std::complex literals if you include <complex> and use the std::complex_literals namespace. This lets you write 3.0 + 4.0i, which makes the code look much more like the math textbooks you probably spent years trying to avoid.




📋 Practical Task

Exercise: AC Circuit Impedance Calculator

In electrical engineering, impedance (Z) is represented as a complex number where the real part is resistance (R) and the imaginary part is reactance (X). The formula is Z = R + jX.

Write a program that does the following:

  1. Define three components:
    • A resistor with 100 ohms (Real: 100, Imag: 0).
    • An inductor with 50 ohms of reactance (Real: 0, Imag: 50).
    • A capacitor with -20 ohms of reactance (Real: 0, Imag: -20).
  2. Calculate the total impedance of these components connected in series (simply sum the complex numbers).
  3. Calculate the total impedance if they were in parallel. The formula for parallel impedance is the reciprocal of the sum of the reciprocals: Z_total = 1 / (1/Z1 + 1/Z2 + 1/Z3).
  4. Print the magnitude (using std::abs) and the phase angle (using std::arg) for both the series and parallel results.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.