C++ Math

Almost every useful program does arithmetic somewhere — computing totals, distances, averages, or physics simulations. C++ gives you two layers of math tools: the built-in arithmetic operators (+, -, *, /, %) that work directly on numeric types, and the <cmath> standard library header, which adds functions like square roots, powers, trigonometry, and rounding. Understanding how both layers behave — especially around integer vs. floating-point arithmetic — is essential, because subtle mistakes here are one of the most common sources of bugs in beginner C++ code.

Overview / How it works

C++ has no single “number” type — it has several, and the type you choose changes how math behaves. The core numeric types are int (whole numbers), double and float (floating-point / decimal numbers), and variants like long or long long for bigger integers. The compiler decides how an operation is evaluated based on the types of its operands, a process called usual arithmetic conversion.

The single most important rule to internalize: if both operands of / are integers, C++ performs integer division — it truncates (discards) the fractional part rather than rounding. So 7 / 2 evaluates to 3, not 3.5. If either operand is a floating-point type, the whole expression is promoted to floating-point and you get the real, fractional result. This is not a bug — it is how the underlying hardware works: integers and floating-point numbers live in different registers and use entirely different bit representations (two’s complement for integers; IEEE 754 for floating-point, which stores a sign, an exponent, and a mantissa/fraction).

Because floating-point numbers are stored as a finite binary approximation, most decimal fractions (like 0.1) cannot be represented exactly — the same way 1/3 cannot be written exactly in decimal. This means floating-point arithmetic carries small rounding errors, which matters when comparing floating-point values for equality (more on this in Common Mistakes).

For anything beyond the four basic operators and modulo, C++ relies on the <cmath> header, which is part of the C++ standard library (inherited from C’s <math.h>). It supplies functions for roots, powers, logarithms, trigonometry, rounding, and classification of numbers. These functions generally take and return double (with overloads for float and long double), and are implemented using efficient hardware instructions or well-tested numerical algorithms — you should always prefer them over hand-rolled math code.

Syntax

Basic arithmetic uses operators directly on values or variables:

result = a + b;   // addition
result = a - b;   // subtraction
result = a * b;   // multiplication
result = a / b;   // division (integer division if both are int)
result = a % b;   // remainder (integers only)

To use the library functions, include the header first:

#include <cmath>

The most commonly used functions are:

Function Meaning Example Result
sqrt(x) Square root of x sqrt(16.0) 4.0
pow(x, y) x raised to the power y pow(2, 10) 1024.0
fabs(x) Absolute value (floating-point) fabs(-3.5) 3.5
abs(x) Absolute value (integer, from <cstdlib>/<cmath>) abs(-7) 7
floor(x) Round down to nearest integer floor(4.9) 4.0
ceil(x) Round up to nearest integer ceil(4.1) 5.0
round(x) Round to nearest integer round(4.5) 5.0
sin(x), cos(x), tan(x) Trigonometric functions (radians) sin(0.0) 0.0
log(x) Natural logarithm (base e) log(1.0) 0.0
log10(x) Base-10 logarithm log10(100.0) 2.0
exp(x) e raised to the power x exp(0.0) 1.0

Examples

Example 1: Integer vs. floating-point division

#include <iostream>
using namespace std;

int main() {
    int a = 17, b = 5;
    double x = 17.0, y = 5.0;

    cout << "Integer division: " << a / b << endl;
    cout << "Integer remainder: " << a % b << endl;
    cout << "Floating-point division: " << x / y << endl;

    double mixed = a / static_cast<double>(b);
    cout << "Mixed division with cast: " << mixed << endl;

    return 0;
}
Output:
Integer division: 3
Integer remainder: 2
Floating-point division: 3.4
Mixed division with cast: 3.4

Notice that a / b with two ints truncates to 3, throwing away the .4. Casting one operand to double with static_cast<double>(b) forces the whole expression into floating-point arithmetic, giving the accurate 3.4. The modulo operator % only works with integer types and returns the remainder after integer division.

Example 2: Using <cmath> functions

#include <iostream>
#include <cmath>
using namespace std;

int main() {
    double num = -25.7;

    cout << "Absolute value: " << fabs(num) << endl;
    cout << "Square root of 25: " << sqrt(25.0) << endl;
    cout << "2 raised to the power 10: " << pow(2, 10) << endl;
    cout << "Floor of 25.7: " << floor(25.7) << endl;
    cout << "Ceiling of 25.2: " << ceil(25.2) << endl;
    cout << "Rounded 25.5: " << round(25.5) << endl;

    return 0;
}
Output:
Absolute value: 25.7
Square root of 25: 5
2 raised to the power 10: 1024
Floor of 25.7: 25
Ceiling of 25.2: 26
Rounded 25.5: 26

Each function returns a double, which is why sqrt(25.0) prints as 5 rather than 5.0cout drops trailing zeros by default. round() rounds half-way values away from zero, so 25.5 becomes 26, not 25.

Example 3: A realistic program — solving a quadratic equation

#include <iostream>
#include <cmath>
using namespace std;

int main() {
    double a = 2.0, b = -7.0, c = 3.0;
    double discriminant = pow(b, 2) - 4 * a * c;

    if (discriminant > 0) {
        double root1 = (-b + sqrt(discriminant)) / (2 * a);
        double root2 = (-b - sqrt(discriminant)) / (2 * a);
        cout << "Two real roots: " << root1 << " and " << root2 << endl;
    } else if (discriminant == 0) {
        double root = -b / (2 * a);
        cout << "One real root: " << root << endl;
    } else {
        cout << "No real roots (discriminant is negative)." << endl;
    }

    return 0;
}
Output:
Two real roots: 3 and 0.5

This program combines everything: pow() computes b squared, sqrt() finds the square root of the discriminant, and ordinary operators combine them using the quadratic formula. Branching on the sign of the discriminant with if/else if/else handles the three mathematically distinct cases.

Under the hood

When the compiler sees x / y, it looks at the types of x and y at compile time — not at runtime — and picks the corresponding machine instruction. For two ints, the CPU’s integer-division instruction runs, which naturally truncates toward zero (this is guaranteed by the C++ standard since C++11). For doubles, the CPU’s floating-point unit (FPU) performs division according to IEEE 754, producing a result with roughly 15-17 significant decimal digits of precision, stored as sign + exponent + mantissa bits.

Functions like sqrt and the trigonometric functions are not simple formulas — they’re implemented with iterative numerical algorithms (or dedicated CPU instructions, such as sqrtsd on x86) tuned for speed and accuracy across the entire range of representable numbers. That is why you should always call sqrt() instead of writing your own approximation: the standard library version has been tested far more thoroughly than anything you’d write by hand.

Common Mistakes

Mistake 1: Expecting integer division to give a fractional answer.

int total = 7, count = 2;
double average = total / count;   // WRONG: still does integer division first
cout << average;                  // prints 3, not 3.5

The division happens before the result is assigned to average. Since both total and count are int, C++ computes 7 / 2 as integer division (3) and only then converts 3 to 3.0 for storage. Fix it by casting an operand to double before the division:

double average = static_cast<double>(total) / count;  // 3.5

Mistake 2: Comparing floating-point numbers with ==.

double result = 0.1 + 0.2;
if (result == 0.3) {          // WRONG: almost never true
    cout << "Equal";
}

Because 0.1 and 0.2 cannot be represented exactly in binary floating-point, 0.1 + 0.2 actually evaluates to something like 0.30000000000000004, which is not equal to 0.3. Instead, compare within a small tolerance:

#include <cmath>
if (fabs(result - 0.3) < 1e-9) {
    cout << "Equal enough";
}

Best Practices

  • Cast at least one operand to a floating-point type before dividing when you need a fractional result.
  • Never compare floating-point values with ==; use a small epsilon tolerance instead.
  • Include <cmath> whenever you use functions like sqrt, pow, or floor — don’t rely on it being included transitively by another header.
  • Use pow(x, 2) sparingly for simple squaring — x * x is faster and avoids unnecessary floating-point conversion for integers.
  • Watch for division by zero: integer division by zero crashes the program (undefined behavior), while floating-point division by zero produces inf or nan instead of crashing — check for zero divisors explicitly when it matters.
  • Remember that trigonometric functions expect radians, not degrees — convert with degrees * (M_PI / 180.0) or degrees * acos(-1.0) / 180.0 if M_PI isn’t available on your compiler.

Practice Exercises

  1. Write a program that asks the user for the radius of a circle and prints its area (πr²) and circumference (2πr) using pow() or plain multiplication.
  2. Write a program that computes the average of three int test scores and prints it as a decimal (e.g., scores 90, 85, 70 should print an average of 81.6667, not 81).
  3. Write a program that takes the lengths of two legs of a right triangle and computes the hypotenuse using sqrt and pow. Test it with legs 3 and 4 — the expected output is 5.

Summary

  • C++ has separate integer and floating-point arithmetic; dividing two ints truncates the result instead of rounding.
  • Cast an operand with static_cast<double>() to force floating-point division when you need a fractional answer.
  • The <cmath> header provides sqrt, pow, fabs, floor, ceil, round, trigonometric functions, logarithms, and more.
  • Floating-point numbers are binary approximations, so never compare them for exact equality with ==; use a tolerance instead.
  • Trigonometric functions work in radians, and division by zero behaves differently for integers (crash) versus floating-point (inf/nan).