Chapter 3
12 min read
Section 16 of 261

Modular Arithmetic

Mathematical Foundations

Learning Objectives

Modular arithmetic is the algebra of remainders. It is one of the smallest pieces of mathematics that pays the largest dividends in computing: hashing, cryptography, pseudo-random generators, error-correcting codes, circular buffers, parsers for time and dates, and an entire branch of competitive programming all live inside the world of amodna \bmod n. By the end of this section you will be able to:

  1. State and use the congruence relation ab(modn)a \equiv b \pmod{n} and reason about equivalence classes.
  2. Manipulate modular expressions algebraically, knowing exactly when addition, subtraction, multiplication, and division are and are not safe.
  3. Compute abmodna^b \bmod n in O(logb)O(\log b) time by repeated squaring, in both Python and TypeScript with BigInt.
  4. Find modular inverses via the extended Euclidean algorithm and via Fermat's little theorem when nn is prime.
  5. Recognize when modular arithmetic is the right tool, from hash tables and Rabin–Karp to RSA and circular buffers.
  6. Avoid the classical landmines: negative numbers, signed-vs-unsigned overflow, non-prime moduli, and bad hash-table sizes.
Why this matters: almost every fast algorithm that touches integers eventually reduces them modn\bmod n. The hash table you use a thousand times a day is built on it. The HTTPS handshake that protects your bank login is built on it. Once modular arithmetic feels natural, large stretches of algorithms stop looking magical.

Definition: Congruence Modulo n

Fix an integer n1n \geq 1, called the modulus. Two integers aa and bb are congruent modulo nn, written

ab(modn)a \equiv b \pmod{n},

if nn divides their difference: n(ab)n \mid (a - b). Equivalently, they leave the same remainder when divided by nn. So 175(mod12)17 \equiv 5 \pmod{12} because both leave remainder 55 after division by 1212, and 1212 divides 175=1217 - 5 = 12.

Three equivalent definitions

For integers a,ba, b and modulus n1n \geq 1, the following are equivalent:
  1. ab(modn)a \equiv b \pmod n.
  2. n(ab)n \mid (a - b), i.e. ab=kna - b = kn for some integer kk.
  3. aa and bb have the same remainder under integer division by nn.

Equivalence classes

Congruence is an equivalence relation: reflexive, symmetric, and transitive. So it carves the integers into nn disjoint equivalence classes, often written [0],[1],,[n1][0], [1], \ldots, [n-1]. The set of these classes, with the inherited addition and multiplication, is the ring Z/nZ\mathbb{Z}/n\mathbb{Z}. From the algorithm designer's point of view, Z/nZ\mathbb{Z}/n\mathbb{Z} is just "the integers {0,1,,n1}\{0, 1, \ldots, n-1\} with arithmetic that wraps around at nn."


Clock Arithmetic: The Pictorial Definition

A 12-hour clock is the canonical picture of arithmetic modulo 1212. If it is currently 7 o'clock and you wait 8 hours, the hour hand does not point to 15—it points to 3, because 15 mod 12 = 3. The clock automatically reduces every result back into {0,1,,11}\{0, 1, \ldots, 11\}. In symbols:

7+83(mod12)7 + 8 \equiv 3 \pmod{12}.

Three observations are worth memorizing because every other identity will follow from them:

  • The clock has exactly nn positions, labeled 0,1,,n10, 1, \ldots, n-1. There is no "12" on a mod-12 clock; the position you would call 12 is the same physical position as 0.
  • Walking forward by kk steps and walking backward by nkn - k steps land you in the same place. Negation is a wrap-around.
  • Multiplication is repeated addition, so it also wraps—but with a twist we will examine: not every nonzero number on the clock has a multiplicative inverse.

Interactive: The Modular Wheel

Drag the modulus slider to change nn, pick an operation (add kk, multiply by kk, or one binary-expansion step of squaring), and click Step to watch the pointer hop around the wheel. The history pane shows the residue stream, exactly what an algorithm sees.

01234567891011
current state: 0 (mod 12)
history (last 8):
00 start 0

Things to try

Set n=12n = 12, op = + k, k=7k = 7, and step repeatedly: you walk every position before returning to 00, because gcd(7,12)=1\gcd(7, 12) = 1. Now try k=4k = 4: you only ever land on multiples of 44. The orbit length is n/gcd(k,n)n / \gcd(k, n)—a small fact with very large consequences for hashing.

The Algebra of Congruences

The reason modular arithmetic is so useful in algorithms is that addition, subtraction, and multiplication respect congruence. If aa(modn)a \equiv a' \pmod n and bb(modn)b \equiv b' \pmod n, then

  • a+ba+b(modn)a + b \equiv a' + b' \pmod n,
  • abab(modn)a - b \equiv a' - b' \pmod n,
  • abab(modn)a \cdot b \equiv a' \cdot b' \pmod n.

The practical corollary is the rule that lets you keep numbers small at every step of a computation:

(a+b)modn=((amodn)+(bmodn))modn(a + b) \bmod n = ((a \bmod n) + (b \bmod n)) \bmod n,

(ab)modn=((amodn)(bmodn))modn(a \cdot b) \bmod n = ((a \bmod n) \cdot (b \bmod n)) \bmod n.

This is why a sum like (123456987654+314159)mod1000000007(123456 \cdot 987654 + 314159) \bmod 1000000007 can be computed without ever forming a number larger than about 101810^{18}: reduce after every multiplication.

Why division is special

The same convenience does not hold for division. From 60(mod6)6 \equiv 0 \pmod 6 we cannot divide both sides by 2 to conclude 30(mod6)3 \equiv 0 \pmod 6—that statement is false. Division in Z/nZ\mathbb{Z}/n\mathbb{Z} requires a modular inverse, which only exists when gcd(a,n)=1\gcd(a, n) = 1. We will return to this in a few sections.

A clean proof sketch

Why does multiplication respect congruence? If a=a+sna = a' + sn and b=b+tnb = b' + tn, then

ab=(a+sn)(b+tn)=ab+n(at+bs+stn)a b = (a' + sn)(b' + tn) = a' b' + n(a' t + b' s + s t n).

The second term is a multiple of nn, so abab(modn)ab \equiv a' b' \pmod n. The proofs for addition and subtraction are identical and shorter.


Negative Numbers and the C/Python Divide

Mathematically, the canonical residue of aa mod nn is the unique integer in {0,1,,n1}\{0, 1, \ldots, n-1\}. Real programming languages do not all agree on this convention.

Language(-7) % 3 evaluates toWhy
Python2Result has the sign of the divisor; result is in [0, n-1] when n > 0.
C, C++, Java, Go, Rust, JavaScript-1Result has the sign of the dividend; truncation toward zero.
Mathematica, R (with %%)2Floor-division semantics, like Python.

Python and Mathematica use floor division: a=na/n+(amodn)a = n \lfloor a / n \rfloor + (a \bmod n) with the remainder always nonnegative. C and friends use truncation toward zero: a=ntrunc(a/n)+(amodn)a = n \cdot \mathrm{trunc}(a / n) + (a \bmod n) with the remainder taking the sign of aa.

The canonicalization trick

In any language with truncating %, force a nonnegative remainder with the idiom
📝text
1r = ((a % n) + n) % n;   // works in C, C++, Java, Go, Rust, JS, TS
Use this everywhere a residue is fed into an array index, a hash table slot, or a lookup. The single extra + n costs one cycle and removes an entire bug class.

Modular Exponentiation by Repeated Squaring

Many algorithms—Rabin–Karp, Miller–Rabin primality, RSA, Diffie–Hellman, polynomial hashing, modular combinatorics—need to compute abmodna^b \bmod n for large bb. Computing aba^b naively, then reducing, is hopeless: with a=3a = 3 and b=109b = 10^9 the intermediate number has about half a billion digits.

The fix is the identity

ab={1if b=0,(ab/2)2if b is even,a(a(b1)/2)2if b is odd.a^b = \begin{cases} 1 & \text{if } b = 0, \\ (a^{b/2})^2 & \text{if } b \text{ is even}, \\ a \cdot (a^{(b-1)/2})^2 & \text{if } b \text{ is odd}. \end{cases}

Each level of recursion halves bb, so the depth is log2b+1\lfloor \log_2 b \rfloor + 1. The iterative form walks the binary representation of bb from least to most significant bit, maintaining two registers: base=a2imodn\text{base} = a^{2^i} \bmod n and a running result\text{result}. Wherever the bit is 11, multiply the result by the current base; in either case, square the base.

Python implementation

Modular exponentiation in Python
🐍power_mod.py
1Signature

Three integer inputs: the base a, the exponent b (non-negative), and the modulus n. Python integers are unbounded, so we never overflow.

6Edge case n == 1

Modulo 1 collapses every integer to 0; the loop below would also produce 0, but special-casing keeps the contract crisp.

EXAMPLE
power_mod(7, 100, 1) == 0
9Initialize the running product

result starts at the multiplicative identity 1. We will multiply it by selected powers of a as we walk b's binary expansion.

10Canonicalize the base

Reduce a mod n once, up front. Every later product stays bounded by n^2, which fits comfortably in 64 bits when n <= 2^32.

EXAMPLE
If a = 1234567 and n = 13, base becomes 1234567 % 13 = 11.
11Loop while bits remain

Each iteration consumes one bit of b. Total iterations are floor(log2(b)) + 1, giving O(log b) work.

12Test the lowest bit of b

b & 1 is 1 when the least significant bit of b is set. This bit decides whether the current power of a contributes to the answer.

EXAMPLE
If b = 13 (binary 1101), the bits encountered are 1, 0, 1, 1.
13Fold the current base into the result

When the bit is 1, multiply result by base = a^(2^i) mod n, then reduce. This is the only place result changes.

EXAMPLE
After bit 0 with base = 7, result = 1 * 7 % n = 7.
14Square the base for the next bit

We always square, even when we did not multiply, because the next bit corresponds to a^(2^(i+1)). Squaring once per bit gives the logarithmic speedup.

EXAMPLE
If base was 7 mod 13, next base = 49 mod 13 = 10.
15Shift b right by one

Discard the bit we just consumed. The loop terminates when b becomes 0, after exactly floor(log2(b_initial)) + 1 iterations.

17Return the result

result is in [0, n-1] because every assignment ends with a `% n` reduction.

7 lines without explanation
1def power_mod(a: int, b: int, n: int) -> int:
2    """Return a**b mod n in O(log b) multiplications.
3
4    Works for any non-negative b and any n >= 1.
5    """
6    if n == 1:
7        return 0                       # everything is 0 mod 1
8
9    result = 1
10    base = a % n                       # canonicalize the base
11    while b > 0:
12        if b & 1:                      # current low bit is 1?
13            result = (result * base) % n
14        base = (base * base) % n       # square for the next bit
15        b >>= 1                        # shift to next bit of exponent
16
17    return result

TypeScript implementation with BigInt

In any fixed-precision language, the product resultbase\text{result} \cdot \text{base} can overflow even when both operands are below nn. For cryptographic-size moduli the only sane option is an arbitrary-precision integer type. JavaScript and TypeScript ship one: bigint.

Modular exponentiation in TypeScript with BigInt
📘powerMod.ts
1BigInt signature

All three parameters are bigint. Mixing bigint and number in a single arithmetic expression throws a TypeError, which forces consistent precision.

2n == 1 short-circuit

Same edge case as Python. Note the literal 1n: trailing n is the bigint literal suffix.

3Reject negative exponents

Negative exponents demand a modular inverse, which only exists when gcd(a, n) = 1. Throw a RangeError so callers cannot silently produce wrong answers.

8Initial result

1n is the bigint multiplicative identity.

9Canonical residue of a

JS's % is truncating, so a % n can be negative when a is negative. ((a % n) + n) % n forces the result into [0, n-1].

EXAMPLE
((-7n) % 3n + 3n) % 3n === 2n.
11Loop on the exponent

We mutate a local copy `exp` instead of `b` to keep the function's input parameters semantically read-only.

12Test least significant bit

exp & 1n returns 1n if the lsb is set, 0n otherwise. The explicit `=== 1n` is required because bigint values are not booleans.

13Multiply when bit is 1

Same logic as Python: when the bit set, fold the current squared base into result and reduce mod n.

15Square for next bit

base goes from a^(2^i) to a^(2^(i+1)), all mod n. Bigint multiplication is exact, so no intermediate truncation can corrupt the running powers.

16Right-shift exp

>>= for bigint is the arithmetic right shift, equivalent to integer division by 2 since exp is non-negative.

18Return the bigint result

Always in [0n, n - 1n]. For an RSA-sized modulus (2048 bits) this routine runs in a few thousand bigint multiplications and milliseconds of wall time.

7 lines without explanation
1export function powerMod(a: bigint, b: bigint, n: bigint): bigint {
2  if (n === 1n) return 0n;
3  if (b < 0n) {
4    throw new RangeError("powerMod: negative exponent requires a modular inverse");
5  }
6
7  let result = 1n;
8  let base = ((a % n) + n) % n;        // canonical residue, even if a < 0
9  let exp = b;
10  while (exp > 0n) {
11    if ((exp & 1n) === 1n) {
12      result = (result * base) % n;
13    }
14    base = (base * base) % n;
15    exp >>= 1n;
16  }
17  return result;
18}

Overflow trap in fixed-precision languages

In C/C++ with uint64_t, the product (ab)modn(a \cdot b) \bmod n with a, b &lt; n &lt; 2^{63} overflows 64 bits. Real implementations either widen to __int128, use Montgomery or Barrett reduction, or fall back to a double-based correction trick. Python and BigInt hide the problem; in any language with fixed-width integers, you must face it.

Interactive: Watching Repeated Squaring

The visualizer below traces every iteration of power_mod(a, b, n). The binary expansion of bb is highlighted, and each row shows whether the current bit triggered a multiplication and what the running result becomes. The number of steps is exactly the number of bits in bb: that is the O(logb)O(\log b) guarantee, made physical.

binary expansion of b = 20: 10100 (reading right-to-left, lsb first)
target: ab mod n = 720 mod 13 = 3
step 1 / 5
ibitbase = a^(2^i) mod nactionresult mod n
007skip (bit is 0)1

Try this

Set a=7,b=12,n=13a = 7, b = 12, n = 13. Step through and watch the result land on 11. That is not a coincidence: 7121(mod13)7^{12} \equiv 1 \pmod{13} is Fermat's little theorem in action, which we treat next.

Modular Inverses

The modular inverse of aa modulo nn is the unique residue a1{0,,n1}a^{-1} \in \{0, \ldots, n-1\} satisfying

aa11(modn)a \cdot a^{-1} \equiv 1 \pmod n.

It exists if and only if gcd(a,n)=1\gcd(a, n) = 1. The proof is constructive: Bézout's identity guarantees integers x,yx, y with ax+ny=1a x + n y = 1, and then xmodnx \bmod n is the inverse. The tool that finds x,yx, y is the extended Euclidean algorithm.

Method 1: Extended Euclidean

Modular inverse via extended Euclidean algorithm
🐍mod_inverse.py
1ext_gcd signature

Returns three integers (g, x, y). g is gcd(a, b), and (x, y) are Bezout coefficients satisfying the linear identity a*x + b*y = g.

3Base case b == 0

gcd(a, 0) is |a|, and the trivial identity a * 1 + 0 * 0 = a gives x = 1, y = 0. The recursion bottoms out here.

5Recursive call on (b, a mod b)

Standard Euclidean step: gcd(a, b) = gcd(b, a mod b). The depth is O(log min(a, b)) by the Fibonacci worst case.

EXAMPLE
ext_gcd(252, 105) -> ext_gcd(105, 42) -> ext_gcd(42, 21) -> ext_gcd(21, 0).
6Lift the Bezout identity

Given b*x1 + (a%b)*y1 = g, substitute a%b = a - (a//b)*b to get a*y1 + b*(x1 - (a//b)*y1) = g. Hence the new (x, y) = (y1, x1 - (a//b)*y1).

11Reduce a before invoking ext_gcd

Calling with a % n keeps the numbers small and ensures we work with the canonical residue.

12Inverse-existence check

If gcd(a, n) != 1, no inverse exists. Raise rather than returning a meaningless number.

EXAMPLE
mod_inverse(6, 9) raises because gcd(6, 9) = 3.
14Canonical residue of x

Bezout's x can be negative; `x % n` in Python returns the unique value in [0, n-1].

EXAMPLE
mod_inverse(3, 11) returns 4, since 3 * 4 = 12 ≡ 1 (mod 11).
7 lines without explanation
1def ext_gcd(a: int, b: int) -> tuple[int, int, int]:
2    """Return (g, x, y) with a*x + b*y == g == gcd(a, b)."""
3    if b == 0:
4        return a, 1, 0
5    g, x1, y1 = ext_gcd(b, a % b)
6    return g, y1, x1 - (a // b) * y1
7
8
9def mod_inverse(a: int, n: int) -> int:
10    """Return a^{-1} mod n; raises if gcd(a, n) != 1."""
11    g, x, _ = ext_gcd(a % n, n)
12    if g != 1:
13        raise ValueError(f"inverse does not exist: gcd({a}, {n}) = {g}")
14    return x % n

Method 2: Fermat's little theorem (when n is prime)

If pp is prime and gcd(a,p)=1\gcd(a, p) = 1, then ap11(modp)a^{p-1} \equiv 1 \pmod p, so multiplying both sides by a1a^{-1} gives the closed form

a1ap2(modp)a^{-1} \equiv a^{p-2} \pmod p.

Combined with power_mod, this is a one-liner that runs in O(logp)O(\log p) time. Competitive programmers reach for it constantly because p=109+7p = 10^9 + 7 is prime.

🐍python
1def mod_inverse_prime(a: int, p: int) -> int:
2    """Inverse of a mod p when p is prime and gcd(a, p) = 1."""
3    return power_mod(a, p - 2, p)

Which method to use

Use the extended Euclidean inverse when the modulus is composite, or when you want a single, self-contained primitive that always works given gcd(a,n)=1\gcd(a, n) = 1. Use Fermat for prime moduli when you already have a fast power_mod available—the code is shorter and easier to audit.

Fermat's Little Theorem

Stated cleanly: for any prime pp and any integer aa with gcd(a,p)=1\gcd(a, p) = 1,

ap11(modp)a^{p-1} \equiv 1 \pmod p.

Equivalently, for every integer aa (no coprimality needed), apa(modp)a^p \equiv a \pmod p. The proof, due to Euler, observes that the map xax(modp)x \mapsto a x \pmod p permutes {1,2,,p1}\{1, 2, \ldots, p-1\}, so the product of those residues equals the product of their aa-multiples. Cancel the common product, and the identity drops out.

Why algorithms care

  • Cheap inverses mod a prime, as we just saw.
  • Probabilistic primality testing. Pick a random aa; if an1≢1(modn)a^{n-1} \not\equiv 1 \pmod n, then nn is composite. The contrapositive is the basis of the Fermat test, refined into the Miller–Rabin test you will meet in Chapter 37.
  • RSA correctness. The key derivation in RSA uses Fermat (and its generalization, Euler's theorem) to guarantee that decryption inverts encryption.

A Glimpse of the Chinese Remainder Theorem

Suppose moduli n1,n2,,nkn_1, n_2, \ldots, n_k are pairwise coprime, with product N=n1n2nkN = n_1 n_2 \cdots n_k. The Chinese Remainder Theorem says the system of congruences

xr1(modn1),xr2(modn2),,xrk(modnk)x \equiv r_1 \pmod{n_1}, \quad x \equiv r_2 \pmod{n_2}, \quad \ldots, \quad x \equiv r_k \pmod{n_k}

has a unique solution modulo NN, and there is an explicit formula for it. Conceptually, residues mod NN can be split into independent residues mod each nin_i and reassembled. Algorithmically this means: a single problem on a huge modulus can be replaced by several smaller, independent problems—massive speed wins for big-integer multiplication, RSA decryption (via pp and qq separately), and signal processing.

We will treat CRT properly in Chapter 37 once we have its full algorithmic context. For now, just remember: it is the structural reason that composite moduli factor cleanly into their prime parts.


Why Algorithms Care About Modular Arithmetic

Modular arithmetic is one of the most leveraged primitives in computing. A non-exhaustive tour:

DomainWhere the modulus shows upOperation that matters
Hash tablesBucket index = h(k) mod mChoose m prime, far from powers of 2
Rolling hashes (Rabin–Karp)Polynomial hash mod a large primeAdd and remove characters in O(1)
Pseudo-random generatorsLinear congruential X_{n+1} = (a X_n + c) mod mPeriod analysis via gcd and prime factors
Cryptography (RSA, ECC, Diffie–Hellman)Big-integer modular exponentiationpower_mod with 2048+ bit n
Circular buffers / ring queuesnext index = (i + 1) mod nWrap-around without branches
Hash table probingProbe sequence (h + i) mod m or (h + c1 i + c2 i^2) mod mCoverage of the table
Competitive counting problemsAll answers reduced mod 10^9 + 7 or 998244353Inverse via Fermat for division
Calendar and timeDay-of-week mod 7, week-of-year mod 52Zeller-like formulas
Music and signal processing12-tone equal temperament, FFT mod a primeNumber-theoretic transforms
Distributed systemsConsistent-hashing rings of size 2^32 or 2^64Server placement and lookup

Worked example: Rabin–Karp polynomial hashing

To find a pattern PP of length mm inside a text TT of length nn, define a hash for any window T[i..i+m1]T[i..i+m-1] by treating its characters as digits in base BB mod a large prime pp:

Hi=(j=0m1T[i+j]Bm1j)modpH_i = \Big( \sum_{j=0}^{m-1} T[i+j] \cdot B^{m-1-j} \Big) \bmod p.

Sliding the window by one position is then an O(1)O(1) operation:

Hi+1=((HiT[i]Bm1)B+T[i+m])modpH_{i+1} = \big( (H_i - T[i] \cdot B^{m-1}) \cdot B + T[i+m] \big) \bmod p.

Modular arithmetic keeps every intermediate small enough to fit in a 64-bit word; without it, the hash itself would have mlogBm \log B bits and updating it would be linear, not constant, in mm.


Edge Cases and Pitfalls

1. Negative numbers in C-family languages

We have already covered the canonicalization idiom. The bug is so common that some teams ban raw % in favor of a positiveMod wrapper.

2. Hashing with m=2km = 2^k

It is tempting to take the modulus to be a power of two, because xmod2kx \bmod 2^k is a bitmask. But this throws away every bit of xx above position kk. If the high bits of your hash function carry the entropy (very common), the table degenerates and collisions explode. Use a prime modulus for hash tables, or hash with a strong mixing function before masking.

3. Inverse does not exist

Calling mod_inverse(6, 9) is a bug, not a number. Always check gcd(a,n)=1\gcd(a, n) = 1, or design the modulus so it is prime.

4. Off-by-one in circular indexing

For a buffer of capacity nn, the next index after ii is (i+1)modn(i + 1) \bmod n and the previous is (i+n1)modn(i + n - 1) \bmod n. Writing (i1)modn(i - 1) \bmod n in C will return 1-1 for i=0i = 0—a memory bug, not a wrap-around.

5. Overflow in fixed-width languages

With 64-bit integers, (ab)modn(a \cdot b) \bmod n overflows whenever n232n \gtrsim 2^{32}. Use 128-bit intermediates (__int128 in C++, BigInteger in Java) or Montgomery/Barrett reduction.


Summary

ConceptKey formula or fact
Congruencea ≡ b (mod n) iff n | (a − b)
Algebra(a ± b) mod n and (a · b) mod n distribute over the inner mods
Negative residue((a % n) + n) % n produces the canonical [0, n−1] form
Fast exponenta^b mod n in O(log b) by repeated squaring
Inverseexists iff gcd(a, n) = 1; computed by extended Euclidean or Fermat (when n prime)
Fermat's little theorema^(p−1) ≡ 1 (mod p) for prime p, gcd(a, p) = 1
CRTPairwise coprime moduli combine into one unique residue mod their product

Modular arithmetic is the connective tissue between integer algebra and the bounded-precision world of computer arithmetic. Once the four habits—reduce early, canonicalize negatives, use repeated squaring, watch for non-existent inverses—become reflex, the rest of cryptography, hashing, and number-theoretic algorithms reads like applied common sense.

Quick Check

Use Fermat's little theorem to compute 7^20 mod 13.

Quick Check

A hash table of capacity m = 2^16 stores keys via h(k) = k mod m. What is the most likely failure mode if the hash function h tends to return values whose low 8 bits are nearly constant?


Exercises

Computation

  1. Compute by hand: (17)mod5(-17) \bmod 5 in both Python and C semantics.
  2. Use repeated squaring on paper to compute 313mod73^{13} \bmod 7. Show the binary expansion of 1313 and the running product at each step.
  3. Find 71mod117^{-1} \bmod 11 two different ways: extended Euclidean, and Fermat's little theorem.
  4. Show that 66 has no inverse modulo 99. What about modulo 1111?

Implementation

  1. Implement power_mod recursively (split on parity of bb) and verify it agrees with the iterative version on 1000 random inputs.
  2. Write a Rabin–Karp substring search using rolling polynomial hashing modulo p=109+7p = 10^9 + 7. Verify the result on a known case before trusting it; collisions are real.
  3. Build a circular buffer of capacity 8 using (i+1)mod8(i + 1) \bmod 8 for advance and (i+7)mod8(i + 7) \bmod 8 for retreat. Stress-test it with random push/pop sequences.

Conceptual

  1. Prove that if ab(modn)a \equiv b \pmod n and cd(modn)c \equiv d \pmod n, then acbd(modn)a c \equiv b d \pmod n. Where in the proof do you use n(ab)n \mid (a - b)?
  2. Suppose mm is the size of a hash table and hh is a hash function. Argue that if mm shares a large factor with the typical period of hh, you should expect clustering. (This is the practical reason for prime moduli.)
  3. Why does Fermat's little theorem fail for composite nn? Find an aa with an1≢1(modn)a^{n-1} \not\equiv 1 \pmod{n} when n=15n = 15.

With logarithms, summations, induction, probability, and now modular arithmetic in hand, you possess the entire mathematical kit a working algorithm designer needs day-to-day. The next chapter turns this kit on its first major target: Recursion Mastery.

Loading comments...