Basic Math
This section is a run-through of the basic math operators available in C++.
Table of Contents
- Available Math Operators
- Order of Operations
- Modulus
- Exponents
- Common Mathematical Functions
- Modify-and-Assign Operators
- Unary Increment and Decrement
- Floating Point Rounding Errors
- Floating Point Equality
- Integer Overflow
- Further Reading
Available Math Operators
Like most programming languages, C++ uses the following symbols for the basic math operations:
- Addition:
+
- Subtractions:
-
- Multiplication:
*
- Division:
\
- Remainder (Modulus):
%
- Grouping Parenthesis:
()
⚡ Warning:
Most math operations are safe, but dividing by zero will crash a C++ program.
Order of Operations
PFMMDAS order of operations rules are applied:
- P: Parenthesis First
- F: Function Calls Next
- MMD: Modulus, Multiplication, Division (From Left to Right)
- AS: Addition and Substraction (From Left to Right)
🎵 Note:
This is a much simplified version of the precedence rules. See the complete table here.
Modulus
The modulus operator %
calculates the remainder of a division.
The expression a % b
means: What remains after taking away all groups of b
from a
.
So, for example, 15 % 4
has a modulus of 3, because 4 goes into 15 three times with 2 remaining.
Modulus is commonly used to determine if a number is even or odd:
#include <iostream>
int main() {
int number;
std::cout << "Please enter a whole number: ";
std::cin >> number;
std::cout << "The number " << number << " is ";
if (number % 2 == 0) {
std::cout << "even.\n";
} else {
std::cout << "odd.\n";
}
}
Exponents
Exponents are used to multiply a number with itself any number of times.
C++ does not have an exponent operator, instead we use the std::pow()
function from the <cmath>
header.
For example, 2 * 2 * 2 * 2
could be written std::pow(2, 4)
.
Remember that with floating point numbers we also have a special syntax that represents powers of ten:
We can write 3 * std::pow(10, 23)
as 3e23
using scientific notation.
⚡ Warning:
It’s very easy to cause an integer overflow when using std::pow
.
Common Mathematical Functions
The <cmath>
library provides ways to:
- Compute square root or cubic root:
std::sqrt()
andstd::cbrt
- Round up, down, and trucate:
std::ceil()
andstd::floor()
andstd::truncate()
- Compute Trigonometric Functions:
std::cos
andstd::sin
and others. - Computer Exponentials and Logs:
std:exp
andstd:log
and others.
See cmath
at cplusplus.com for all available functions.
Modify-and-Assign Operators
We can pair the equals operator with other math operators to modify and assign the result back to a variable.
int dreams{ 4 };
dreams += 3; // Same as: dreams = dreams + 3
dreams -= 1; // Same as: dreams = dreams - 1
dreams /= 2; // Same as: dreams = dreams / 2
dreams *= 5; // Same as: dreams = dreams * 5
dreams %= 2; // Same as: dreams = dreams % 2
Unary Increment and Decrement
Like other C-influenced languages we have increment (++
) and decrement (--
) operators.
let milesFromHome{ 14333 }; // Miles away from everything you hold dear.
milesFromHome++; // Up to 14334. Sames as: milesFromHome += 1
milesFromHome--; // Back to 14333. Same as: milesFromHome -= 1
milesFromHome--; // Down to 14332
++milesFromHome; // Prefix increment and decrements work too.
These unary operators have a very high precedence with respect to the other mathematical operators. See the full operator precedence table.
Floating Point Rounding Errors
Not all numbers can be stored precisely in a fixed number of binary digits.
Take the result of 1/3
for example:
- Decimal result:
0.33333333...
(The threes continue infinitely.) - When stored as binary:
0.01010101...
(The pattern continue infinitely.)
Or even the result of 1/10
:
- In decimal we can be precise:
0.1
- But when stored in binary:
0.000110011..
(Infinite digits still required.)
⚡ Warning:
C++ floating point numbers should always be considered approximations.
Floating Point Equality
The approximations in floating point math make some code error prone:
#include <iostream>
#include <iomanip> // For std::setprecision()
int main() {
// Floating point comparisons are hard:
if (0.1 + 0.2 == 0.3) {
std::cout << "This will never print!\n";
}
// Increasing the display precision to see why:
std::cout << std::setprecision(17) << 0.1 + 0.2 << "\n";
// For this reason, looping with floats is bug-prone:
for(double value = -1.0; value <= 1.0; value += 0.2) {
std::cout << value << std::endl;
if (value == 0) {
std::cout << "This will also never print!\n";
}
}
}
Integer Overflow
Integer math can be problematic too. C++ will not stop you from accidentally assigning an out-of-range a value for a particular type.
short secondsInDay{ 60 * 60 * 24 }; // 86,400 is larger than the maximum short!
You also need to watch for variables that could increment or decrement past range limits:
#include <iostream>
int main() {
short overflowShort = 32767; // Maximum short.
unsigned int overflowInt= 0; // Minimum unsigned int.
std::cout << "Before Overflow:\n";
std::cout << overflowShort << "\n"; // 32767
std::cout << overflowInt << "\n"; // 0
overflowShort++; // One greater than max short.
overflowInt--; // One less than min unsigned int.
std::cout << "After Overflow:\n";
std::cout << overflowShort << "\n"; // -32768
std::cout << overflowInt << "\n"; // 4294967295
}
⚡ Warning:
Watch out for integer overflow as it results in undefined behavior.