HOWTO · C++
How to Use the Modulo Operator in C++
This article introduces how to use the modulo operator in C++, covering its applications in checking even or odd numbers, implementing cyclic behavior, and utilizing it in algorithms. Learn practical examples and enhance your coding skills with clear explanations and code snippets. Perfect for beginners and experienced programmers alike.
On this page
The C++ % operator returns the remainder after integral division. For example, 10 % 3 is 1. It works with integral types, including signed integers; it does not accept floating-point operands. The divisor must be nonzero. Use the result for parity checks, cyclic positions, and bounded bucket indexes, while accounting for signed values where needed.
What the C++ % Operator Returns
For integers a and b, a % b is the remainder left after a / b. C++ truncates integer division toward zero, so 10 / 3 is 3 and 10 % 3 is 1. Both operands must have integral types; using % with a non-integral operand makes the expression ill-formed. The divisor must also be nonzero, because a zero divisor causes undefined behavior.
This small program shows a typical positive calculation:
#include <iostream>
int main() {
const int dividend = 17;
const int divisor = 5;
std::cout << dividend % divisor << '\n';
}
2
The % operator is not defined for floating-point values. Use std::fmod from <cmath> when you need a floating-point remainder.
How % Works with Signed Integers
For signed operands, integer division truncates toward zero and a nonzero remainder has the dividend’s sign. Thus -10 % 3 is -1, while 10 % -3 is 1; in both cases the quotient times the divisor plus the remainder equals the dividend. This behavior is specified by C++, not left to compiler choice.
Because a negative remainder stays negative, % alone does not always produce a nonnegative index. If you need a normalized result, require a positive modulus m, store value % m in a remainder variable, and add m only when that remainder is negative. Since the remainder is greater than -m, this produces a result in [0, m) without an intermediate sum that can overflow. The quotient must also be representable: % has undefined behavior when the corresponding integer division quotient cannot be represented, such as the minimum value of a signed type % -1. The remainder identity above does not apply to that undefined case.
Check Parity and Cycle Through Values with %
An integer is even when value % 2 == 0; otherwise it is odd. This works for negative integers too, because an exact multiple of two has remainder zero.
For cyclic indexing, use a positive collection size and a nonnegative position:
#include <iostream>
int main() {
const int values[] = {10, 20, 30};
const int count = static_cast<int>(sizeof(values) / sizeof(values[0]));
for (int position = 0; position < 5; ++position) {
const int index = position % count;
std::cout << values[index] << '\n';
}
}
10
20
30
10
20
The array contains three elements, so each index is in the range 0 through 2; the sequence of positions repeats as the loop advances. This pattern assumes the collection has at least one element. For positions that may be negative, normalize the remainder before using it as an index.
Use Remainders in Hashing and Random Number Ranges
A hash table can use a remainder to map a nonnegative key into a table with tableSize buckets: key % tableSize. This requires tableSize > 0. If keys can be negative, normalize the result as described above before converting it to an index. Real hash tables also need a hash function and a collision strategy; the remainder only selects a bucket range.
For random integers, do not assume std::rand() % bound is evenly distributed: if the generator’s number of possible values is not a multiple of bound, some results occur more often. Prefer std::uniform_int_distribution with a random engine when you want an inclusive integer range:
#include <iostream>
#include <random>
int main() {
std::mt19937 engine(12345);
std::uniform_int_distribution<int> range(1, 6);
std::cout << range(engine) << '\n';
}
6
The distribution’s parameters define the included lower and upper bounds. With this seed, engine, and tested standard library implementation of std::uniform_int_distribution, the example prints 6. C++ does not require the distribution to map engine outputs identically across standard library implementations, so the exact output and sequence are not portable; they are repeatable only when both the engine and distribution implementation are the same. Use a seed source appropriate to your application when you need different sequences.
Use std::modulus as a Function Object
std::modulus in <functional> is a function object that applies % to two values. It is useful when an algorithm expects a callable object rather than an operator expression:
#include <functional>
#include <iostream>
int main() {
const std::modulus<int> remainder;
std::cout << remainder(17, 5) << '\n';
}
2
Its operands follow the same integral and nonzero-divisor rules as %. For ordinary expressions, a % b is usually the clearest spelling.