Complex Demo — Complex Number Arithmetic
The sangi Complex<T> class handles complex numbers uniformly from double all the way up to the arbitrary-precision Float type.
This page walks through three demos that illustrate representative use cases.
Demo 1: Basic complex arithmetic
Compute the four arithmetic operations along with absolute value (abs), argument (arg), and conjugate (conj) for Complex<double>.
Declaring using sangi::literals enables user-defined literals such as 3.0_i for intuitive imaginary-number notation.
Demo 1 source code
// demo1_basic.cpp — Complex<double> basic arithmetic
#include <math/core/Complex.hpp>
#include <iostream>
#include <iomanip>
using namespace sangi;
using namespace sangi::literals; // enables 3.0_i literals
int main() {
std::cout << std::setprecision(6);
std::cout << "=== Complex<double> Basic Operations ===\n";
// Build complex numbers with user-defined literals
auto a = 2.0 + 3.0_i; // (2, 3)
auto b = 1.0 - 1.0_i; // (1, -1)
std::cout << "a = " << a << "\n";
std::cout << "b = " << b << "\n\n";
// Four arithmetic operations
std::cout << "a + b = " << (a + b) << "\n";
std::cout << "a - b = " << (a - b) << "\n";
std::cout << "a * b = " << (a * b) << "\n";
std::cout << "a / b = " << (a / b) << "\n\n";
// Absolute value, argument, conjugate
std::cout << "abs(a) = " << abs(a) << "\n";
std::cout << "arg(a) = " << arg(a) << " (rad)\n";
std::cout << "conj(a) = " << conj(a) << "\n";
return 0;
}
sangi::literals namespace, 3.0_i is converted to Complex<double>(0, 3.0).
Combined with standard arithmetic operators, this lets you write code that closely matches the mathematical notation.
Demo 2: Mandelbrot set membership
Determine whether a complex number $c$ belongs to the Mandelbrot set by iterating the recurrence $z_{n+1} = z_n^2 + c$ with $z_0 = 0$. If $|z| > 2$ has not been reached after 100 iterations, treat $c$ as a member of the set. We classify several lattice points and print the result.
Demo 2 source code
// demo2_mandelbrot.cpp — Mandelbrot set membership
#include <math/core/Complex.hpp>
#include <iostream>
#include <iomanip>
#include <vector>
using namespace sangi;
bool isMandelbrot(Complex<double> c, int maxIter, int& iterOut,
double& absOut) {
Complex<double> z(0.0, 0.0);
for (int i = 0; i < maxIter; ++i) {
z = z * z + c;
if (abs(z) > 2.0) {
iterOut = i + 1;
absOut = abs(z);
return false; // diverges → not in the set
}
}
iterOut = maxIter;
absOut = abs(z);
return true; // bounded → in the set
}
int main() {
std::cout << std::setprecision(6) << std::fixed;
std::cout << "=== Mandelbrot Set Membership ===\n";
std::vector<Complex<double>> points = {
{0.0, 0.0}, {0.25, 0.0}, {-1.0, 0.0}, {1.0, 0.0},
{-0.5, 0.5}, {0.3, 0.5}, {-1.5, 0.0}, {-0.75, 0.1}
};
constexpr int maxIter = 100;
for (auto& c : points) {
int iter;
double absZ;
bool inSet = isMandelbrot(c, maxIter, iter, absZ);
std::cout << "c = " << std::setw(16) << std::left << c
<< ": " << (inSet ? "IN " : "OUT")
<< " (|z| = " << absZ
<< ", iter = " << iter << ")\n";
}
return 0;
}
Demo 3: Complex mathematical functions
Verify Euler's formula $e^{i\pi} = -1$ with Complex<double>, then evaluate the complex versions of sin, cos, exp, log, and sqrt.
Finally, use the arbitrary-precision Complex<Float> to verify $e^{i\pi} + 1 = 0$ to 100 digits.
Demo 3 source code
// demo3_math_functions.cpp — complex math functions and high-precision computation
#include <math/core/Complex.hpp>
#include <math/core/Float.hpp>
#include <iostream>
#include <iomanip>
#include <numbers>
using namespace sangi;
using namespace sangi::literals;
int main() {
// --- Euler's formula ---
std::cout << "=== Euler's Formula: exp(i*pi) ===\n";
auto ipi = Complex<double>(0.0, std::numbers::pi);
auto euler = exp(ipi);
std::cout << "exp(i*pi) = " << euler << "\n";
std::cout << "exp(i*pi) + 1 = " << (euler + 1.0) << "\n";
std::cout << " (the imaginary error is double rounding noise)\n";
// --- Complex math functions ---
std::cout << "\n=== Complex Math Functions ===\n";
auto z = 1.0 + 1.0_i;
std::cout << std::setprecision(6);
std::cout << "z = " << z << "\n";
std::cout << "sin(z) = " << sin(z) << "\n";
std::cout << "cos(z) = " << cos(z) << "\n";
std::cout << "exp(z) = " << exp(z) << "\n";
std::cout << "log(z) = " << log(z) << "\n";
std::cout << "sqrt(z) = " << sqrt(z) << "\n";
// --- Arbitrary-precision Complex<Float> ---
std::cout << "\n=== High-Precision: Complex<Float> (100 digits) ===\n";
constexpr int digits = 100;
Float::setDefaultPrecision(digits);
Float pi = Float::pi(digits);
Complex<Float> ipi_hp(Float(0), pi);
Complex<Float> result = exp(ipi_hp) + Complex<Float>(Float(1));
std::cout << "exp(i*pi) + 1 =\n";
std::cout << " real: " << result.real().toString(digits) << "\n";
std::cout << " imag: " << result.imag().toString(digits) << "\n";
return 0;
}
Complex<double>, Euler's formula leaves a rounding error of $\approx 10^{-16}$.
Switching to Complex<Float> verifies $e^{i\pi} + 1 = 0$ at arbitrary precision.
sangi's Complex<T> lets you change precision purely by swapping the template parameter — the API stays exactly the same.
Source code and how to build
example_complex.cpp (full source)
// example_complex.cpp
// Complex<T> demo: basic operations, Mandelbrot membership, math functions,
// high-precision Complex<Float>
#include <math/core/Complex.hpp>
#include <math/core/mp/Float.hpp>
#include <iostream>
#include <iomanip>
#include <vector>
#include <numbers>
using namespace sangi;
using namespace sangi::literals;
// --- Demo 1: Basic arithmetic ---
void demo1_basic() {
std::cout << std::setprecision(6);
std::cout << "=== Complex<double> Basic Operations ===\n";
auto a = 2.0 + 3.0_i;
auto b = 1.0 - 1.0_i;
std::cout << "a = " << a << "\n";
std::cout << "b = " << b << "\n\n";
std::cout << "a + b = " << (a + b) << "\n";
std::cout << "a - b = " << (a - b) << "\n";
std::cout << "a * b = " << (a * b) << "\n";
std::cout << "a / b = " << (a / b) << "\n\n";
std::cout << "abs(a) = " << abs(a) << "\n";
std::cout << "arg(a) = " << arg(a) << " (rad)\n";
std::cout << "conj(a) = " << conj(a) << "\n";
}
// --- Demo 2: Mandelbrot set membership ---
bool isMandelbrot(Complex<double> c, int maxIter, int& iterOut,
double& absOut) {
Complex<double> z(0.0, 0.0);
for (int i = 0; i < maxIter; ++i) {
z = z * z + c;
if (abs(z) > 2.0) {
iterOut = i + 1;
absOut = abs(z);
return false;
}
}
iterOut = maxIter;
absOut = abs(z);
return true;
}
void demo2_mandelbrot() {
std::cout << "\n=== Mandelbrot Set Membership ===\n";
std::cout << std::setprecision(6) << std::fixed;
std::vector<Complex<double>> points = {
{0.0, 0.0}, {0.25, 0.0}, {-1.0, 0.0}, {1.0, 0.0},
{-0.5, 0.5}, {0.3, 0.5}, {-1.5, 0.0}, {-0.75, 0.1}
};
constexpr int maxIter = 100;
for (auto& c : points) {
int iter;
double absZ;
bool inSet = isMandelbrot(c, maxIter, iter, absZ);
std::cout << "c = " << std::setw(16) << std::left << c
<< ": " << (inSet ? "IN " : "OUT")
<< " (|z| = " << absZ
<< ", iter = " << iter << ")\n";
}
}
// --- Demo 3: Math functions and high-precision computation ---
void demo3_math() {
std::cout << "\n=== Euler's Formula: exp(i*pi) ===\n";
std::cout << std::setprecision(6) << std::defaultfloat;
auto ipi = Complex<double>(0.0, std::numbers::pi);
auto euler = exp(ipi);
std::cout << "exp(i*pi) = " << euler << "\n";
std::cout << "exp(i*pi) + 1 = " << (euler + 1.0) << "\n";
std::cout << " (imag error is double rounding noise)\n";
std::cout << "\n=== Complex Math Functions ===\n";
auto z = 1.0 + 1.0_i;
std::cout << "z = " << z << "\n";
std::cout << "sin(z) = " << sin(z) << "\n";
std::cout << "cos(z) = " << cos(z) << "\n";
std::cout << "exp(z) = " << exp(z) << "\n";
std::cout << "log(z) = " << log(z) << "\n";
std::cout << "sqrt(z) = " << sqrt(z) << "\n";
std::cout << "\n=== High-Precision: Complex<Float> (100 digits) ===\n";
constexpr int digits = 100;
Float::setDefaultPrecision(digits);
Float pi = Float::pi(digits);
Complex<Float> ipi_hp(Float(0), pi);
Complex<Float> result = exp(ipi_hp) + Complex<Float>(Float(1));
std::cout << "exp(i*pi) + 1 =\n";
std::cout << " real: " << result.real().toString(digits) << "\n";
std::cout << " imag: " << result.imag().toString(digits) << "\n";
}
int main() {
demo1_basic();
demo2_mandelbrot();
demo3_math();
return 0;
}
For full API details, see the Complex API reference.
Build and run
cd sangi
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release --target example-complex
examples\Release\example-complex.exe