Primality Tests
Algorithms to decide whether an integer is prime. From exact trial division to fast probabilistic / deterministic Miller–Rabin.
This lesson follows CP-Algorithms — Primality tests.
Related: Integer Factorization, Montgomery Multiplication, Divisor Functions.
Trial division
A composite n has a divisor d with 2 ≤ d ≤ √n (because if every proper divisor were > √n, the cofactor would be < √n). Scan d = 2 … ⌊√n⌋; any hit ⇒ composite.
bool isPrime(int x) {
for (int d = 2; d * d <= x; d++) {
if (x % d == 0)
return false;
}
return x >= 2;
}
Optimize by special-casing 2 and only testing odd d (or a wheel) — same ideas as in Integer Factorization.
🧪 Trial division demo
Fermat primality test
Fermat’s little theorem: if p is prime and gcd(a,p)=1, then
a^{p−1} ≡ 1 (mod p)
Pick 2 ≤ a ≤ n−2. If a^{n−1} ≢ 1 (mod n), then a is a Fermat witness — n is composite.
If the congruence holds, n is only probably prime: a might be a Fermat liar. Repeat with random bases.
bool probablyPrimeFermat(int n, int iter = 5) {
if (n < 4)
return n == 2 || n == 3;
for (int i = 0; i < iter; i++) {
int a = 2 + rand() % (n - 3);
if (binpower(a, n - 1, n) != 1)
return false;
}
return true;
}
Use binary exponentiation for a^{n−1} mod n.
Carmichael numbers
Some composites satisfy a^{n−1} ≡ 1 (mod n) for every a coprime to n — e.g. 561 = 3·11·17. Fermat catches them only if you luck into gcd(a,n) ≠ 1. There are only 646 Carmichael numbers below 10⁹, so Fermat is still used when you need raw speed.
Miller–Rabin
Write odd n−1 = 2^s · d with d odd. Factor Fermat’s congruence:
a^{n−1} − 1 = (a^{2^{s−1}d} + 1) ⋯ (a^d + 1)(a^d − 1)
If n is prime it must divide one factor. For base a, check whether
a^d ≡ 1 (mod n)
or
a^{2^r d} ≡ −1 (mod n) for some 0 ≤ r ≤ s−1
If neither holds, a is a witness (proven composite). Otherwise a is a strong liar / n is a strong probable prime.
Unlike Carmichael numbers, at most 1/4 of bases can be strong liars. Each random iteration has ≥ 75% chance to catch a composite.
🧪 Deterministic Miller–Rabin (64-bit bases)
Speed tip
Before MR, trial-divide by the first few primes. About 88% of integers have a prime factor < 100.
Deterministic Miller–Rabin
Miller: bases ≤ O((ln n)²) suffice. Bach: a ≤ 2 (ln n)².
Practical tables (no randomness):
| Range | Bases |
|---|---|
| 32-bit | 2, 3, 5, 7 (smallest fail: 3 215 031 751) |
| 64-bit | first 12 primes: 2…37 |
| 64-bit (7 bases) | 2, 325, 9375, 28178, 450775, 9780504, 1795265022 — also exclude prime factors of those bases |
bool MillerRabin(u64 n) {
if (n < 2) return false;
int r = 0;
u64 d = n - 1;
while ((d & 1) == 0) { d >>= 1; r++; }
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
if (n == a) return true;
if (check_composite(n, a, d, r)) return false;
}
return true;
}
Check: primality tests
Primality tests
1 / 5Trial division only needs to check divisors up to…
Pick an answer to see if you are right.
Practice drills
Input: integer n (0 ≤ n ≤ 10⁶). Print 1 if prime, else 0.
Practice problems
From CP-Algorithms:
Cheat sheet
| Test | Kind | Notes |
|---|---|---|
| Trial division | Deterministic | O(√n); fine for small n |
| Fermat | Probabilistic | Fast; Carmichael liars |
| Miller–Rabin | Probabilistic | Error ≤ 4^{−k} with k rounds |
| MR + fixed bases | Deterministic | 32/64-bit tables |
| Pre-filter | — | Trial tiny primes first |