std::complex
Class template for complex number arithmetic with real and imaginary parts, arithmetic operators, math functions, and C++14 literals.
std::complexsince C++98A class template in <complex> representing a complex number as a (real, imaginary) pair, providing arithmetic operators, equality comparison, stream I/O, and a complete set of complex-valued mathematical functions.
Overview
std::complex<T> parameterises the scalar type. The standard mandates three explicit specialisations β float, double, and long double β and since C++11 guarantees binary layout compatibility with C99's _Complex types: a complex<double> occupies exactly two consecutive double values, so reinterpreting to double[2] or passing to a C API expecting double _Complex is well-defined.
The class provides:
- Full arithmetic:
+,-,*,/, compound-assignment forms, and unary negation. - Equality comparison:
==and!=. No ordering operators exist β complex numbers have no natural total order. - Stream I/O:
operator<<writes(real,imag),operator>>reads the same format. - Free-function mathematics: magnitude, argument, squared norm, conjugate, projection, polar construction, and all transcendental functions overloaded for complex arguments.
- C++14 user-defined literals for concise construction.
Integer and other non-floating-point template arguments are not required to work; implementations may reject them.
Syntax
#include <complex>
template<typename T>
class std::complex; // primary template; T should be a floating-point type
std::complex<float> cf;
std::complex<double> cd;
std::complex<long double> cl;Construction methods:
std::complex<double> a; // default: (0, 0)
std::complex<double> b(3.0, 4.0); // (3 + 4i)
std::complex<double> c{3.0, 4.0}; // C++11 brace-init, identical semantics
auto p = std::polar(5.0, 0.9273); // from magnitude and phase angle (radians)
// C++14 literals β requires the using directive
using namespace std::complex_literals; // C++14
auto d = 3.0 + 4.0i; // std::complex<double>
auto df = 3.0f + 4.0if; // std::complex<float>
auto dl = 3.0l + 4.0il; // std::complex<long double>Member access:
std::complex<double> z(3.0, 4.0);
double r = z.real(); // 3.0
double i = z.imag(); // 4.0
z.real(6.0); // setter β added in C++11
z.imag(8.0); // setter β added in C++11Examples
Arithmetic and standard math functions
#include <complex>
#include <iostream>
#include <cmath>
int main() {
using C = std::complex<double>;
C z1{3.0, 4.0};
C z2{1.0, -2.0};
C sum = z1 + z2; // (4, 2)
C prod = z1 * z2; // (11, -2)
C quot = z1 / z2; // complex division: (z1 * conj(z2)) / norm(z2)
double mag = std::abs(z1); // 5.0 β magnitude (L2 norm)
double phase = std::arg(z1); // ~0.927 rad β phase angle, equivalent to atan2(imag, real)
double nsq = std::norm(z1); // 25.0 β SQUARED magnitude: reΒ² + imΒ²
C cj = std::conj(z1); // (3, -4) β complex conjugate
C pr = std::proj(z1); // projection onto Riemann sphere β C++11
C root = std::sqrt(C{-1.0, 0.0}); // (0, 1) β principal square root
C ex = std::exp(C{0.0, M_PI}); // β (-1, Ξ΅) β Euler's identity
std::cout << z1 << '\n'; // (3,4)
std::cout << prod << '\n'; // (11,-2)
std::cout << mag << '\n'; // 5
}Polynomial evaluation and DFT
#include <complex>
#include <vector>
#include <cmath>
// Evaluate a real-coefficient polynomial at a complex point β Horner's method
std::complex<double> eval_poly(const std::vector<double>& coeffs,
std::complex<double> z) {
std::complex<double> result{};
for (auto it = coeffs.rbegin(); it != coeffs.rend(); ++it)
result = result * z + *it;
return result;
}
// Compute a single DFT bin directly (O(N), for illustration)
std::complex<double> dft_bin(const std::vector<double>& x, std::size_t k) {
using namespace std::complex_literals; // C++14
const std::size_t N = x.size();
std::complex<double> acc{};
for (std::size_t n = 0; n < N; ++n) {
double angle = -2.0 * M_PI * static_cast<double>(k * n) / N;
acc += x[n] * std::exp(1.0i * angle);
}
return acc;
}Interoperating with C APIs
Since C++11 the standard guarantees that complex<T> has the same binary layout as T[2]:
#include <complex>
#include <vector>
// Hypothetical C API that takes an array of (re, im) pairs as doubles
extern "C" void fft_inplace(double* data, std::size_t n);
void run_fft(std::vector<std::complex<double>>& buf) {
// reinterpret_cast here is explicitly permitted by the C++11 standard
fft_inplace(reinterpret_cast<double*>(buf.data()), buf.size());
}Best Practices
Choose double by default. std::complex<float> saves memory on large arrays, but precision loss compounds through iterative algorithms. Profile and measure before downgrading.
Use std::polar for phase-domain construction. Writing r * std::cos(theta) and r * std::sin(theta) manually is verbose and slightly less precise; the library version may exploit fused multiply-add or trigonometric co-computation internally.
Compare distances with std::norm, not std::abs. To check whether two complex values are within eps of each other, write std::norm(z1 - z2) < eps * eps. This avoids a square root and is the idiomatic pattern for proximity tests.
Scope complex literals tightly. Put using namespace std::complex_literals; inside a function, not at file scope, to avoid naming conflicts β particularly with user-defined or third-party _i literals.
Prefer free-function std::abs over manual hypot. std::abs(z) is numerically safe against intermediate overflow; std::sqrt(z.real()*z.real() + z.imag()*z.imag()) overflows for large components even when the true magnitude is representable.
Common Pitfalls
std::norm is squared magnitude, not the L2 norm. The name is actively misleading. std::norm(z) returns reΒ² + imΒ². To get |z|, use std::abs(z). Confusing these introduces silent numeric errors that only appear at scale.
No std::numeric_limits specialisation. std::numeric_limits<std::complex<double>> is not specialised. It compiles but returns the unspecialised-template defaults β typically 0 or false for every member. Query limits through the scalar type: std::numeric_limits<double>::epsilon().
Mixed-precision types do not implicitly convert. std::complex<double> and std::complex<float> are unrelated types. Mixing them in arithmetic is a compile error. Convert explicitly: static_cast<std::complex<double>>(cf).
operator>> format is strict. std::cin >> z expects (3,4) β parentheses, a comma, no spaces inside. A bare 3.0 4.0 will not parse correctly; the stream enters a failed state.
i suffix requires the using directive. operator""i, operator""if, and operator""il live in std::literals::complex_literals, not in the global namespace or even in std. A bare using namespace std; does not bring them in. Without using namespace std::complex_literals;, 4.0i is a syntax error.
See Also
<cmath>β scalar overloads ofsin,cos,exp, etc.;<complex>provides separate overloads for complex argumentsstd::valarrayβ expression-template array type that composes naturally withcomplex<T>elements for vectorised numerics- Operator overloading β
std::complexis a canonical example of arithmetic operator overloading for user-defined numeric types