C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
236: The <complex> Header for Complex Numbers
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:
- 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).
- Calculate the total impedance of these components connected in series (simply sum the complex numbers).
- 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). - Print the magnitude (using
std::abs) and the phase angle (usingstd::arg) for both the series and parallel results.
There are no comments for now.