20 topics
/
← Back to Quick Reference
Topic 17

Math Functions

cmath · Trig · Logarithms · Random · Numeric Limits · C++20 Constants

C++17 · Advanced Reference

Math in C++

01

Headers 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. 1.Never compare floats with == — use an epsilon tolerance.
  2. 2.pow(2, 10) is integer literals → double → may lose precision. Use 1 << 10 for integer powers of 2.
  3. 3.std::abs(-5) requires <cstdlib> for int; <cmath> for double — wrong header gives wrong overload.
  4. 4.rand() is not uniformly distributed — always use <random>.

Performance tips

  1. 1.Use float instead of double where precision allows — SIMD can process 2× as many floats per cycle.
  2. 2.std::hypot avoids overflow on large inputs — don't write sqrt(x*x + y*y).
  3. 3.log1p(x) and expm1(x) are more accurate than log(1+x) and exp(x)-1 for small x.
  4. 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 truncround: 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; }
radiansAll 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_PIPOSIX extension, not standard C++. Use std::numbers::pi (C++20) or define your own constexpr.
std::numbersC++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 / expm1Numerically 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
mt19937Mersenne Twister — fast, high quality, 623-dimensional equidistribution. The standard choice.
random_deviceHardware entropy source for seeding. Slow — call once to seed mt19937, not for every number.
uniform_int_distributionGuaranteed uniform distribution on [a, b]. Use instead of rng() % n.
normal_distributionGaussian 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::piC++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.