Exercises — Module 05 (Arithmetic)
Self-contained problems on this module's material — the classical algorithms (addition, multiplication), Karatsuba's divide-and-conquer multiply, the binary gcd, and probabilistic primality/factoring. You can work every one without the books: each states the problem in full, gives a hint to peek at when stuck, and a worked answer sketch to check against after you try. Computational answers here are reproduced by the code you write in the lab (or a few lines at a REPL).
Ratings follow Knuth's scale (00–50; M = needs mathematics, ▶ = especially
instructive). Where a problem mirrors a TAOCP exercise its section is noted for
readers who own Volume 2.
Tracking
| # | Topic | Rating | Status |
|---|---|---|---|
| 1 | The carry in Algorithm A never exceeds | 15 | ⬜ |
| 2 | ▶ Exact digit-multiplication count of Algorithm M | 25 | ⬜ |
| 3 | Karatsuba's constant and the empirical crossover | 30 | ⬜ |
| 4 | ▶ Binary gcd vs. Euclid on Fibonacci pairs | 28 | ⬜ |
| 5 | Mini-project: Pollard's rho factoring | 35 | ⬜ |
Problems
1. The carry in Algorithm A never exceeds (rating 15 · cf. §4.3.1)
Problem. Numbers are stored in radix (the lab uses ) as digit strings with . Algorithm A adds them digit by digit: at position it forms , writes , and carries into the next position. Prove that the carry is always or , so a single extra limb suffices to hold the whole sum.
Hint. Bound from above in the worst case. What is the largest possible value of if you already know ? Set up an induction on .
Answer sketch. Induct on . Initially . Suppose the incoming carry satisfies . Then
so the outgoing carry . The bound is preserved, so at every step. (Check: base gives ; base gives , both with carry .) Because the final carry is at most , one extra digit always holds it — this is why an -digit + -digit sum needs at most digits, and why hardware chains a single carry line.
2. ▶ Exact digit-multiplication count of Algorithm M (rating 25 · cf. §4.3.1)
Problem. Algorithm M multiplies an -digit number by an -digit number with two nested loops: for each digit of it runs across every digit of , forming the product . Count the exact number of single-digit multiplications Algorithm M performs, as a function of and , and argue it does not depend on the digit values. What does this say about the asymptotic cost?
Hint. The inner statement runs once for every pair . How many such pairs are there? Are any pairs skipped for particular inputs?
Answer sketch. The outer loop runs over ( passes) and for each, the inner loop runs over ( digit products), with no early exits. So Algorithm M always performs exactly
regardless of the operands' values — every digit of meets every digit of exactly once. (The additions/carries add only lower-cost operations.) Hence "schoolbook" multiplication is , i.e. for equal-size operands. This exact, value-independent count is precisely the baseline that Karatsuba (Problem 3) must beat, and knowing it to the digit is what lets you tune the Karatsuba cutover.
3. Karatsuba's constant and the empirical crossover (rating 30 · cf. §4.3.3)
Problem. Karatsuba multiplies two -digit numbers with three half-size
products instead of four, giving the recurrence .
(a) Solve the recurrence: what is the exponent in ,
and how many leaf (single-digit) products does the pure recursion make for
? (b) Explain why, despite the smaller exponent, real implementations
(and your big_mul_karatsuba) switch to the classical method below
a cutoff of a few dozen limbs — and describe how you would locate that crossover
empirically.
Hint. Unroll the recursion tree: each internal node spawns children and the depth is . Count the leaves. For (b), compare constants, not just exponents: which method has the smaller hidden constant, and at what size does finally undercut once constants are included?
Answer sketch. (a) Recursion depth is and each level triples the number of subproblems, so there are leaves. By the recursion-tree (master) argument the leaves dominate the merge work, giving
(Verified leaf counts for : , , , versus classical — the classical/Karatsuba ratio
grows from to .) (b) Karatsuba's smaller exponent hides a larger
constant: three recursive calls plus several additions/shifts and
recursion overhead per level. For small that overhead exceeds the
digit-products classical multiply saves, so
until is a few dozen limbs. To find the crossover empirically: time both
big_mul and big_mul_karatsuba on random inputs of increasing size, and set
the cutoff at the size where Karatsuba first wins consistently. Below it,
big_mul_karatsuba should delegate to the classical routine.
4. ▶ Binary gcd vs. Euclid on Fibonacci pairs (rating 28 · cf. §4.5.2)
Problem. Consecutive Fibonacci numbers are Euclid's worst case: every quotient is , so the algorithm makes the most division steps possible for inputs of that size. (a) Show that Euclid's algorithm on makes exactly division steps, and that . (b) Run the binary gcd (Stein's algorithm — shifts and subtractions only) on the same pairs and compare the step counts. Which grows faster, and why is each still ?
Hint. For (a), one Euclid step on produces because ; induct down to the base case. For (b), remember grows like , so — both algorithms' step counts are linear in , hence logarithmic in the operands.
Answer sketch. (a) Since and , we have , so one division step sends . Iterating drives the pair down to , whose division leaves remainder — exactly steps in all, leaving gcd . (Verified: takes ; takes ; takes — always , always gcd .) (b) The binary gcd on the same pairs makes noticeably fewer shift-and-subtract iterations — e.g. Euclid divisions vs. Stein subtractions on — because it removes factors of in bulk and never divides. The exact count depends on the variant, but both are : Euclid's and Stein's iterations are each linear in , and . The instructive point: Fibonacci inputs make Euclid do its maximum work, yet division-free binary gcd is unbothered — trading expensive divisions for cheap shifts is the whole idea.
5. Mini-project: Pollard's rho factoring (rating 35 · cf. §4.5.4)
Problem. Miller–Rabin tells you a number is composite but not what its factors are. Implement Pollard's rho and use it to factor a 60-bit semiprime. Pollard's rho iterates with , detects the cycle with Floyd's tortoise-and-hare, and returns as a nontrivial factor. (a) Explain why this finds a factor in expected iterations. (b) Factor and report the two primes.
Hint. (a) Reduce the iteration modulo an unknown prime factor of : by
the birthday paradox the sequence repeats after about
steps, and when but , the gcd exposes . (b) Use fast modular arithmetic (mul_mod via
u128) from Stage 5, and re-run with a different constant if the gcd comes back
as itself.
Answer sketch. (a) Let be the smallest prime factor of . The map behaves like a random function on the residues, so by the birthday bound the reduced sequence collides after steps. Floyd's cycle finder locates such a collision using iterations; at that point but typically , so is a proper factor. Since , the expected cost is gcd/step operations — for a 60-bit that is on the order of iterations. (b) With and , Floyd's method exposes a factor of
in about iterations (both factors are prime, verifiable with
is_prime_u64) — consistent with the estimate. This is the same
/random-map machinery as Miller–Rabin, turned from a detector of
compositeness into a producer of factors.
Your solutions
Use this space to log your own work — a restated problem, your approach, and how it compared with the sketch above.
Exercise N (rating RR)
Approach. Answer / proof. Compared with the sketch: what you did differently, what you missed.