Skip to content
Theory · Operators and Expressions · lesson 1 of 8

Arithmetic: integer division, remainder, overflow

The operators +, - and * work on whole numbers the same way school arithmetic does. Division is different: when both numbers are int, the result is an int too, and an int has no fractional part.

C++
#include <iostream>

int main() {
    int apples = 17;
    int kids = 5;
    std::cout << apples / kids << '\n';  // 3
    std::cout << apples % kids << '\n';  // 2
}

Seventeen apples shared among five kids give three each, with two apples left over. The / operator produced the quotient, and % produced the remainder.

Integer division

The values an operator works on are called operands. Dividing two integer operands is integer division: the fractional part of the result is discarded, not rounded. So 19 / 5 is also 3, even though 3.8 is closer to four. A negative result is rounded toward zero as well: -17 / 5 is -3, not -4.

If either operand is a double, the other is converted to double, and the division keeps the fraction: 17 / 5.0 is 3.4. Integer division by 0 is undefined behavior: the standard does not say what happens then.

Remainder

The % operator works only on integer operands. The quotient and the remainder are linked: a / b * b + a % b equals a. That is why the remainder takes the sign of the dividend, the left operand:

C++
std::cout << -17 / 5 << ' ' << -17 % 5 << '\n';  // -3 -2
std::cout << 17 / -5 << ' ' << 17 % -5 << '\n';  // -3 2

The remainder helps take a number apart into digits: n % 10 is the last digit, and n / 10 is the number without it. For 253, these are 3 and 25.

Overflow

An int holds numbers from a limited range: where it takes 4 bytes, from -2147483648 to 2147483647. If the result of +, - or * does not fit in this range, an overflow occurs. For int and long long, this is undefined behavior too.

The unsigned type unsigned (full name unsigned int) holds only non-negative numbers. A literal with the u suffix, such as 5u, has type unsigned. For this type, crossing the boundary is well defined: the arithmetic wraps around, and 0 comes again after the maximum.

C++
#include <iostream>

int main() {
    unsigned zero = 0u;
    std::cout << zero - 1u << '\n';  // 4294967295
    std::cout << zero - 1u + 1u << '\n';  // 0
}

The number 4294967295 is the maximum of a 4-byte unsigned. Subtracting from zero crossed the boundary downward, and adding one to the maximum crossed it upward.

Common mistake

The result of dividing two int values is stored in a double variable in the hope of getting a fraction:

C++
#include <iostream>

int main() {
    double half = 5 / 2;  // ✗
    std::cout << half << '\n';  // 2
}

The compiler sees no error, and the program prints 2. First 5 / 2 runs as integer division, and only its result 2 becomes a double. The type of the variable on the left does not affect the division: the operand types do. Write 5 / 2.0, and half gets 2.5.