18.4 Modular Arithmetic

Modular arithmetic is the arithmetic of remainders.

18.4 Modular Arithmetic

Modular arithmetic is the arithmetic of remainders. Instead of tracking the exact value of an integer, we track only its position within a finite cycle. This simple idea transforms many seemingly impossible computations into efficient algorithms and forms the foundation of modern cryptography, hashing, number theory, combinatorics, distributed systems, and competitive programming.

A computer clock provides an intuitive example. If the time is 10 o'clock and we advance 5 hours, the result is 3 o'clock rather than 15 o'clock. The arithmetic wraps around after reaching a fixed boundary.

Modular arithmetic formalizes this behavior.

Problem

Given a positive integer:

m

called the modulus, perform arithmetic while keeping only the remainder after division by m.

Examples:

17 mod 5 = 2
29 mod 7 = 1
100 mod 12 = 4

Instead of working with large integers, computations are performed within a finite set:

0, 1, 2, ..., m-1

This finite structure provides remarkable computational advantages.

Congruence

Two integers are congruent modulo m if they leave the same remainder when divided by m.

Notation:

a ≡ b (mod m)

Definition:

m | (a - b)

In words:

a and b differ by a multiple of m.

Examples:

17 ≡ 2 (mod 5)

because:

17 - 2 = 15

and:

5 | 15

Similarly:

38 ≡ 3 (mod 7)

because:

38 - 3 = 35

and:

7 | 35

Congruence behaves like equality inside modular arithmetic.

Residue Classes

Under modulus:

m = 5

all integers belong to one of five classes:

Class Members
0 ..., -10, -5, 0, 5, 10 ...
1 ..., -9, -4, 1, 6, 11 ...
2 ..., -8, -3, 2, 7, 12 ...
3 ..., -7, -2, 3, 8, 13 ...
4 ..., -6, -1, 4, 9, 14 ...

Every integer belongs to exactly one residue class.

Computations move among these classes rather than among infinitely many integers.

Addition Modulo m

Addition behaves naturally.

If:

a ≡ x (mod m)
b ≡ y (mod m)

then:

a + b ≡ x + y (mod m)

Example:

17 + 24

under modulus:

5

Reduce first:

17 ≡ 2
24 ≡ 4

Then:

2 + 4 = 6

Reduce again:

6 ≡ 1 (mod 5)

Result:

17 + 24 ≡ 1 (mod 5)

Subtraction Modulo m

Subtraction follows the same rule.

Example:

18 - 11

modulo:

5

Reduce:

18 ≡ 3
11 ≡ 1

Compute:

3 - 1 = 2

Result:

2

Therefore:

18 - 11 ≡ 2 (mod 5)

Multiplication Modulo m

Multiplication is also preserved.

If:

a ≡ x (mod m)
b ≡ y (mod m)

then:

ab ≡ xy (mod m)

Example:

17 × 24

modulo:

5

Reduce:

17 ≡ 2
24 ≡ 4

Multiply:

2 × 4 = 8

Reduce:

8 ≡ 3

Therefore:

17 × 24 ≡ 3 (mod 5)

Why Reduction Works

Consider:

a = mq + r

Then:

a ≡ r (mod m)

The multiple:

mq

contributes nothing to the remainder.

Only the residue remains.

Consequently we can reduce intermediate results repeatedly without affecting correctness.

This property is crucial for large-number computations.

Modular Arithmetic in Code

A simple helper:

def mod_add(a, b, m):
    return (a + b) % m

def mod_sub(a, b, m):
    return (a - b) % m

def mod_mul(a, b, m):
    return (a * b) % m

Example:

print(mod_add(17, 24, 5))
print(mod_mul(17, 24, 5))

Output:

1
3

Modular Division

Addition, subtraction, and multiplication always work.

Division is different.

In ordinary arithmetic:

6 ÷ 3 = 2

Under modular arithmetic, division requires an inverse.

Suppose we want:

3x ≡ 1 (mod 7)

Try values:

3×5 = 15

and:

15 ≡ 1 (mod 7)

Therefore:

x = 5

We say:

3⁻¹ ≡ 5 (mod 7)

and write:

1/3 ≡ 5 (mod 7)

Division becomes multiplication by an inverse.

When Inverses Exist

An inverse exists precisely when:

gcd(a,m)=1

Example:

3 mod 7

has an inverse.

Because:

gcd(3,7)=1

Example:

4 mod 8

has no inverse.

Because:

gcd(4,8)=4

not:

1

This criterion connects modular arithmetic directly to the Extended Euclidean Algorithm.

Modular Exponentiation

Consider:

7^1000 mod 13

Direct computation is impossible in practice.

Instead, reduce after every multiplication.

Even better, use repeated squaring.

Naive complexity:

O(n)

Fast exponentiation:

O(log n)

Implementation:

def mod_pow(base, exp, mod):
    result = 1

    while exp > 0:
        if exp & 1:
            result = (result * base) % mod

        base = (base * base) % mod
        exp >>= 1

    return result

Example:

print(mod_pow(7, 1000, 13))

Computes efficiently despite the enormous exponent.

Modular Arithmetic Laws

The following identities always hold.

Addition:

(a+b) mod m
=
((a mod m)+(b mod m)) mod m

Subtraction:

(a-b) mod m
=
((a mod m)-(b mod m)) mod m

Multiplication:

(ab) mod m
=
((a mod m)(b mod m)) mod m

Exponentiation:

(a^k) mod m
=
((a mod m)^k) mod m

These rules permit aggressive reduction during computation.

Negative Numbers

Many languages handle negative remainders differently.

Mathematically:

-3 mod 5 = 2

because:

-3 ≡ 2 (mod 5)

since:

5 | (-3 - 2)

When implementing modular arithmetic, always verify how the programming language defines %.

A safe normalization is:

x = ((x % m) + m) % m

which guarantees:

0 ≤ x < m

Applications

Cryptography

RSA, Diffie-Hellman, elliptic curve cryptography, and digital signatures operate almost entirely in modular arithmetic.

Hash Tables

Hash values are frequently reduced:

hash(key) mod table_size

Scheduling

Cyclic schedules naturally use modular arithmetic.

Circular Buffers

Index wrapping:

(i + 1) mod capacity

Number Theory

Congruences, inverses, and arithmetic functions rely on modular computation.

Competitive Programming

Most counting problems use large prime moduli such as:

1,000,000,007

to prevent overflow.

Common Mistakes

Forgetting Reduction

Intermediate values can grow exponentially.

Reduce frequently.

Assuming Division Always Works

Division requires an inverse.

Not every element has one.

Overflow Before Modulo

Computing:

(a × b) mod m

can overflow before reduction.

Special multiplication techniques may be required for large integers.

Mishandling Negative Values

Different languages produce different remainder behavior.

Always normalize when necessary.

Prime Moduli

Prime moduli possess especially useful properties.

If:

p

is prime, every nonzero element has an inverse.

For modulus:

7

the nonzero residues:

1,2,3,4,5,6

all have inverses.

This property makes prime moduli the preferred choice in cryptography and algorithm design.

Takeaway

Modular arithmetic replaces ordinary equality with congruence classes and performs computations within a finite cyclic system. Addition, subtraction, multiplication, and exponentiation behave predictably under reduction, enabling efficient computation with very large integers. Modular inverses, modular exponentiation, and congruence relations form the foundation of cryptography, hashing, combinatorics, and advanced number theory. Understanding modular arithmetic is essential for every topic that follows in this chapter.