20 topics
← Back to Quick Reference/
Topic 17
MMaatthh FFuunnccttiioonnss
cmath · Trig · Logarithms · Random · Numeric Limits · C++20 Constants
C++17 · Advanced ReferenceMath in C++
01Headers and precision
C++ math lives in <cmath> (functions), <limits>(type bounds), <random> (RNG), and <numbers>(C++20 constants). All <cmath> functions operate on doubleby default — pass float arguments and you get a promotion that may surprise you.
Common pitfalls
- 1.Never compare floats with
==— use an epsilon tolerance. - 2.
pow(2, 10)is integer literals → double → may lose precision. Use1 << 10for integer powers of 2. - 3.
std::abs(-5)requires<cstdlib>for int;<cmath>for double — wrong header gives wrong overload. - 4.
rand()is not uniformly distributed — always use<random>.
Performance tips
- 1.Use
floatinstead ofdoublewhere precision allows — SIMD can process 2× as many floats per cycle. - 2.
std::hypotavoids overflow on large inputs — don't writesqrt(x*x + y*y). - 3.
log1p(x)andexpm1(x)are more accurate thanlog(1+x)andexp(x)-1for smallx. - 4.For integer exponentiation, use repeated squaring — not
pow.
Compile with -ffast-math for ~2–4× floating-point speedup — but it breaks NaN handling and strict IEEE 754 compliance.
Powers · Roots · Rounding · abs
02#include <cmath> // ── Powers & roots ──────────────────────────────────────────── std::sqrt(16.0) // 4.0 — square root std::cbrt(27.0) // 3.0 — cube root std::pow(2.0, 10.0) // 1024.0 — x^y (floating-point) std::hypot(3.0, 4.0) // 5.0 — sqrt(x²+y²), avoids overflow // ── Rounding ────────────────────────────────────────────────── std::floor(3.7) // 3.0 — round toward -∞ std::ceil(3.2) // 4.0 — round toward +∞ std::round(3.5) // 4.0 — round half away from zero std::trunc(3.9) // 3.0 — round toward zero std::round(-3.5) // -4.0 — away from zero // ── Absolute value ──────────────────────────────────────────── std::abs(-5) // 5 — <cstdlib> for int std::abs(-5.0) // 5.0 — <cmath> for double std::fabs(-5.0) // 5.0 — explicit floating-point abs // ── Remainder ───────────────────────────────────────────────── std::fmod(10.5, 3.0) // 1.5 — floating-point remainder (sign = dividend) std::remainder(10.5, 3.0) // -0.5 — IEEE remainder (closest integer)
| hypot(x, y) | sqrt(x²+y²) without overflow. Use for distances and vector magnitudes. |
| pow(x, y) | Floating-point exponentiation. For integer powers, use repeated multiplication — it's exact and faster. |
| round vs trunc | round: half away from zero. trunc: toward zero. floor: toward -∞. ceil: toward +∞. |
| fmod vs % | % only works on integers. fmod is the float equivalent. Sign matches the dividend. |
Trigonometry
03#include <cmath> // ── Trigonometry (arguments in radians) ────────────────────── std::sin(M_PI / 6) // 0.5 — sine std::cos(M_PI / 3) // 0.5 — cosine std::tan(M_PI / 4) // 1.0 — tangent // ── Inverse trig ────────────────────────────────────────────── std::asin(0.5) // π/6 — arcsine, result in [-π/2, π/2] std::acos(0.5) // π/3 — arccosine, result in [0, π] std::atan(1.0) // π/4 — arctangent, result in (-π/2, π/2) std::atan2(y, x) // angle of (x,y) from origin in [-π, π] // ← preferred over atan(y/x) — handles all quadrants // ── Hyperbolic ──────────────────────────────────────────────── std::sinh(x) std::cosh(x) std::tanh(x) // ── Degrees ↔ Radians ───────────────────────────────────────── constexpr double PI = std::numbers::pi; // C++20 <numbers> double toRad(double deg) { return deg * PI / 180.0; } double toDeg(double rad) { return rad * 180.0 / PI; }
| radians | All trig functions use radians. Multiply degrees by π/180 to convert. |
| atan2(y, x) | Preferred over atan(y/x) — correctly handles all four quadrants and x=0. |
| M_PI | POSIX extension, not standard C++. Use std::numbers::pi (C++20) or define your own constexpr. |
| std::numbers | C++20 header providing pi, e, sqrt2, ln2, phi as compile-time constants. |
Logarithms · Exp · Special Values
04#include <cmath> // ── Exponential & logarithm ─────────────────────────────────── std::exp(1.0) // 2.718... — e^x std::exp2(8.0) // 256.0 — 2^x std::expm1(x) // e^x - 1 — accurate for small x std::log(std::numbers::e) // 1.0 — natural log (base e) std::log2(1024.0) // 10.0 — log base 2 std::log10(1000.0) // 3.0 — log base 10 std::log1p(x) // log(1+x) — accurate for small x // ── Special float values ────────────────────────────────────── #include <limits> double inf = std::numeric_limits<double>::infinity(); double nan = std::numeric_limits<double>::quiet_NaN(); double eps = std::numeric_limits<double>::epsilon(); // ~2.22e-16 std::isinf(x) std::isnan(x) std::isfinite(x) // ── Safe float comparison ───────────────────────────────────── bool nearlyEqual(double a, double b, double tol = 1e-9) { return std::abs(a - b) <= tol * std::max(std::abs(a), std::abs(b)); }
| log1p / expm1 | Numerically stable versions of log(1+x) and exp(x)-1 for small x. Use in probability and financial math. |
| epsilon() | Smallest value e such that 1.0 + e != 1.0. The basis for epsilon comparisons. |
| lowest() | Most negative representable value — different from min() which is the smallest positive normal. |
| quiet_NaN() | Not-a-Number. NaN != NaN is always true — use std::isnan() to check. |
Random Number Generation
05#include <random> // ── Correct random number generation ───────────────────────── std::mt19937 rng(std::random_device{}()); // seeded Mersenne Twister // Uniform integer in [1, 6] std::uniform_int_distribution<int> dice(1, 6); int roll = dice(rng); // Uniform float in [0.0, 1.0) std::uniform_real_distribution<double> unit(0.0, 1.0); double r = unit(rng); // Normal (Gaussian) distribution — mean=0, stddev=1 std::normal_distribution<double> normal(0.0, 1.0); double sample = normal(rng); // ── Other distributions ─────────────────────────────────────── std::bernoulli_distribution coin(0.5); // true/false with prob p std::poisson_distribution<int> poisson(4.0); // events per interval std::exponential_distribution<double> exp(1.5); // ── Shuffle a vector ────────────────────────────────────────── std::shuffle(v.begin(), v.end(), rng); // ⚠ Never use: rand() % n — not uniform, implementation-defined seed // std::random_device{}() may be slow — seed once, reuse rng
| mt19937 | Mersenne Twister — fast, high quality, 623-dimensional equidistribution. The standard choice. |
| random_device | Hardware entropy source for seeding. Slow — call once to seed mt19937, not for every number. |
| uniform_int_distribution | Guaranteed uniform distribution on [a, b]. Use instead of rng() % n. |
| normal_distribution | Gaussian bell curve. Specify mean and standard deviation. |
Never use
rand(). It has poor statistical properties, a tiny period, and non-uniform distribution when used with %. Use std::mt19937 + a distribution.Numeric Limits & C++20 Constants
06#include <limits> #include <numbers> // C++20 // ── Integer limits ──────────────────────────────────────────── std::numeric_limits<int>::min() // -2147483648 std::numeric_limits<int>::max() // 2147483647 std::numeric_limits<unsigned>::max() // 4294967295 std::numeric_limits<long long>::max()// 9223372036854775807 // ── Float limits ────────────────────────────────────────────── std::numeric_limits<double>::max() // ~1.8e308 std::numeric_limits<double>::min() // ~2.2e-308 (smallest positive normal) std::numeric_limits<double>::lowest() // ~-1.8e308 (most negative) std::numeric_limits<double>::epsilon() // ~2.2e-16 (machine epsilon) std::numeric_limits<double>::digits10 // 15 (significant decimal digits) // ── C++20 mathematical constants (<numbers>) ────────────────── std::numbers::pi // 3.14159265358979... std::numbers::e // 2.71828182845904... std::numbers::sqrt2 // 1.41421356237309... std::numbers::ln2 // 0.693147180559945... std::numbers::phi // 1.61803398874989... (golden ratio) // Available as templates: std::numbers::pi_v<float>, etc.
| numeric_limits<T>::max() | Largest finite value of type T. Use instead of INT_MAX or DBL_MAX macros. |
| numeric_limits<T>::lowest() | Most negative value. For floats this differs from min() — always use lowest() for the floor. |
| std::numbers::pi | C++20: compile-time double precision π. Prefer over M_PI (POSIX) or hand-coded literals. |
| epsilon() | Machine epsilon — the gap between 1.0 and the next representable double. Use as relative tolerance base. |