The remainder operator (operator%)

The remainder operator (sometimes called the modulo operator) returns what's left over after integer division. For instance, 13 / 3 = 4 with remainder 1, so 13 % 3 = 1. Similarly, 50 / 7 = 7 with remainder 1, so 50 % 7 = 1. This operator only works with integer types.

The remainder operator is particularly useful for checking if one number divides evenly into another. If a % b equals 0, then b divides evenly into a.

#include <iostream>

int main()
{
    std::cout << "Enter a number: ";
    int dividend{};
    std::cin >> dividend;

    std::cout << "Enter a divisor: ";
    int divisor{};
    std::cin >> divisor;

    std::cout << "Remainder: " << dividend % divisor << '\n';

    if ((dividend % divisor) == 0)
        std::cout << dividend << " is evenly divisible by " << divisor << '\n';
    else
        std::cout << dividend << " is not evenly divisible by " << divisor << '\n';

    return 0;
}

Sample runs:

Enter a number: 20
Enter a divisor: 5
Remainder: 0
20 is evenly divisible by 5
Enter a number: 20
Enter a divisor: 6
Remainder: 2
20 is not evenly divisible by 6

When the divisor is larger than the dividend, the result might seem unexpected at first:

Enter a number: 3
Enter a divisor: 10
Remainder: 3
3 is not evenly divisible by 10

This makes sense: 3 / 10 = 0 (integer division) with remainder 3. When the divisor exceeds the dividend, it "fits" zero times, leaving the entire dividend as the remainder.

Execution trace

Here's how 17 % 5 is calculated step-by-step:

Step Operation Result
1 Divide: 17 / 5 3 (integer division truncates)
2 Multiply: 3 * 5 15 (how much 5 "used up")
3 Subtract: 17 - 15 2 (what's left over)

So 17 % 5 = 2. The relationship is: dividend = (dividend / divisor) * divisor + (dividend % divisor).

Key Concept
The remainder operation answers: "If I have 17 items and pack them into groups of 5, how many items are left over?" This makes it perfect for tasks like determining if a number is even/odd, cycling through array indices, or formatting output every N items.

Remainder with negative numbers

The remainder operator handles negative operands. The sign of the result always matches the sign of the dividend (the left operand).

Enter a number: -20
Enter a divisor: 6
Remainder: -2
-20 is not evenly divisible by 6
Enter a number: 20
Enter a divisor: -6
Remainder: 2
20 is not evenly divisible by -6

Notice the remainder's sign matches the first operand in both cases.

Negative number edge cases

Expression Result Why
13 % 5 3 Both positive: 13 = 2*5 + 3
-13 % 5 -3 Negative dividend: sign matches -13
13 % -5 3 Negative divisor: sign matches 13
-13 % -5 -3 Negative dividend: sign matches -13
5 % 13 5 Divisor larger: nothing "fits"
-5 % 13 -5 Sign matches -5
Key Concept
The sign of the remainder ALWAYS matches the sign of the dividend (the first operand). The sign of the divisor never affects the result's sign.

Nomenclature note: The C++ standard refers to this as the "remainder" operator. While commonly called "modulo," that term can be confusing because mathematical modulo differs from C++'s operator% when negative numbers are involved.

For example, mathematically:

  • -17 modulo 5 = 3
  • -17 remainder 5 = -2

We prefer calling it the "remainder" operator for accuracy.

When the dividend might be negative, be careful with comparisons. You might write:

bool isOdd(int number)
{
    return (number % 2) == 1; // fails for negative odd numbers
}

This fails for negative odd numbers like -7, because -7 % 2 equals -1, not 1.

Instead, compare against 0, which works correctly regardless of sign:

bool isOdd(int number)
{
    return (number % 2) != 0; // works for positive and negative
}
Best Practice
When using the remainder operator, compare the result against `0` whenever possible to ensure correct behavior with negative numbers.

Where's the exponent operator?

You won't find an exponent operator in C++. The ^ symbol performs bitwise XOR, not exponentiation (covered in the Bit manipulation with bitwise operators and bit masks lesson).

For exponentiation, include the <cmath> header and use std::pow():

#include <cmath>

double result{std::pow(2.0, 8.0)}; // 2 to the 8th power = 256.0

Note that std::pow() uses double for parameters and return value. Floating-point calculations involve rounding errors, so results may not be perfectly precise even with whole numbers.

For integer exponentiation, you'll need a custom function. Here's an efficient implementation using the "exponentiation by squaring" algorithm:

#include <cassert>
#include <cstdint>
#include <iostream>

// note: exponent must be non-negative
// note: doesn't check for overflow—use with caution
constexpr std::int64_t powint(std::int64_t base, int exponent)
{
    assert(exponent >= 0 && "powint: exponent must be non-negative");

    if (base == 0)
        return (exponent == 0) ? 1 : 0;

    std::int64_t result{1};
    while (exponent > 0)
    {
        if (exponent & 1)  // if exponent is odd
            result *= base;
        exponent /= 2;
        base *= base;
    }

    return result;
}

int main()
{
    std::cout << powint(3, 10) << '\n'; // 3 to the 10th power

    return 0;
}

This outputs:

59049

You don't need to understand the algorithm's internals to use the function.

Related content: We cover assertions in the Assert and static_assert lesson, and constexpr functions in the Constexpr functions lesson.

Advanced note: The constexpr keyword allows compile-time evaluation when used in constant expressions. Otherwise, the function executes normally at runtime.

Caution
Integer exponentiation almost always causes overflow for anything beyond small values. This is likely why the standard library doesn't include such a function.

Here's a safer version that detects overflow:

#include <cassert>
#include <cstdint>
#include <iostream>
#include <limits>

// Safer version that checks for overflow
// note: exponent must be non-negative
// Returns std::numeric_limits<std::int64_t>::max() if overflow occurs
constexpr std::int64_t powint_safe(std::int64_t base, int exponent)
{
    assert(exponent >= 0 && "powint_safe: exponent must be non-negative");

    if (base == 0)
        return (exponent == 0) ? 1 : 0;

    std::int64_t result{1};

    bool negativeResult{false};

    if (base < 0)
    {
        base = -base;
        negativeResult = (exponent & 1);
    }

    while (exponent > 0)
    {
        if (exponent & 1)
        {
            if (result > std::numeric_limits<std::int64_t>::max() / base)
            {
                std::cerr << "powint_safe(): overflow detected\n";
                return std::numeric_limits<std::int64_t>::max();
            }

            result *= base;
        }

        exponent /= 2;

        if (exponent <= 0)
            break;

        if (base > std::numeric_limits<std::int64_t>::max() / base)
        {
            std::cerr << "powint_safe(): base overflow detected\n";
            return std::numeric_limits<std::int64_t>::max();
        }

        base *= base;
    }

    if (negativeResult)
        return -result;

    return result;
}

int main()
{
    std::cout << powint_safe(3, 10) << '\n';  // 3^10 = 59049
    std::cout << powint_safe(30, 10) << '\n'; // overflow, returns max int64

    return 0;
}

Summary

  • Remainder operator (%): Returns what's left over after integer division (e.g., 13 % 3 = 1); also called modulo operator
  • Checking divisibility: If a % b == 0, then b divides evenly into a
  • Sign behavior: The remainder's sign always matches the sign of the dividend (left operand)
  • Terminology: C++ uses "remainder" (not "modulo") because mathematical modulo differs from operator% when negative numbers are involved
  • Comparing remainder results: Always compare against 0 when possible to ensure correct behavior with negative numbers (e.g., number % 2 != 0 instead of number % 2 == 1)
  • No exponent operator: C++ doesn't have an exponentiation operator; ^ performs bitwise XOR instead
  • std::pow(): Use std::pow() from <cmath> for floating-point exponentiation (e.g., std::pow(2.0, 8.0))
  • Integer exponentiation: Requires a custom function; floating-point exponentiation may have rounding errors
  • Overflow risk: Integer exponentiation causes overflow for all but small values; use overflow-checking implementations when needed

The remainder operator is essential for many common programming tasks like checking even/odd numbers or cycling through ranges. Understanding its sign behavior with negative numbers prevents subtle bugs. For exponentiation, use std::pow() for floating-point calculations, but be aware that you'll need custom implementations for integer exponentiation with overflow protection.