| Task | Method | Cost |
|---|---|---|
| one | trial division by and | |
| one | deterministic Miller–Rabin (7 fixed bases) | multiplications per base |
| factor one | Pollard–Brent rho + Miller–Rabin | expected |
| factor many | smallest-prime-factor sieve (Sieves) | each |
| all primes in a range | (segmented) sieve | |
| Mersenne numbers | Lucas–Lehmer | |
| cryptographic sizes, need a certificate | ECPP | heuristic |
| theoretical interest only | AKS | , no unproven hypotheses needed |
Smaller base sets suffice for smaller bounds
is deterministic for ; for ; for . Use a shorter set when the input is bounded — fewer modpows per test.
Three recurring bugs
- is not prime, and must be handled before anything else.
i * i <= noverflows when is near — usei <= n / ior__int128.- Fermat’s test alone is wrong: Carmichael numbers (561, 1105, 1729, …) satisfy for every coprime . Korselt: is Carmichael iff it is squarefree, composite and for every prime . Miller–Rabin’s square-root check is exactly what fixes this.
using u64 = unsigned long long; using u128 = __uint128_t;
u64 mulm(u64 a, u64 b, u64 m) { return (u128)a * b % m; }
u64 powm(u64 a, u64 e, u64 m) { u64 r = 1 % m; for (a %= m; e; e >>= 1, a = mulm(a, a, m)) if (e & 1) r = mulm(r, a, m); return r; }
bool isPrime(u64 n) { // deterministic for all 64-bit n
if (n < 2) return false;
for (u64 p : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) if (n % p == 0) return n == p;
int s = __builtin_ctzll(n - 1); u64 d = (n - 1) >> s;
for (u64 a : {2ULL, 325ULL, 9375ULL, 28178ULL, 450775ULL, 9780504ULL, 1795265022ULL}) {
if (a % n == 0) continue;
u64 x = powm(a, d, n);
if (x == 1 || x == n - 1) continue;
bool comp = true;
for (int i = 1; i < s && comp; i++) { x = mulm(x, x, n); if (x == n - 1) comp = false; }
if (comp) return false; // a witnesses that n is composite
}
return true;
}
u64 pollard(u64 n) { // a nontrivial factor of an odd composite n (Brent, batched gcd)
static mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
if (n % 2 == 0) return 2;
for (;;) {
u64 c = rng() % (n - 1) + 1, y = rng() % n, x = y, ys = y, g = 1, q = 1;
auto f = [&](u64 v) { return (mulm(v, v, n) + c) % n; };
for (u64 r = 1; g == 1; r <<= 1) {
x = y; for (u64 i = 0; i < r; i++) y = f(y);
for (u64 k = 0; k < r && g == 1; k += 128) {
ys = y;
for (u64 i = 0; i < min<u64>(128, r - k); i++) y = f(y), q = mulm(q, x > y ? x - y : y - x, n);
g = std::gcd(q, n);
}
}
if (g == n) do ys = f(ys), g = std::gcd(x > ys ? x - ys : ys - x, n); while (g == 1); // replay the last block
if (g != n) return g; // otherwise the walk closed without splitting: new c
}
}
void factorRec(u64 n, vector<u64>& out) {
if (n == 1) return;
if (isPrime(n)) { out.push_back(n); return; }
u64 d = pollard(n); factorRec(d, out); factorRec(n / d, out);
}
vector<pair<u64, int>> factorize(u64 n) { // sorted (prime, exponent)
vector<u64> ps;
for (u64 p : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) while (n % p == 0) ps.push_back(p), n /= p;
factorRec(n, ps); sort(all(ps));
vector<pair<u64, int>> res; for (u64 p : ps) { if (sz(res) && res.back().first == p) res.back().second++; else res.push_back({p, 1}); }
return res;
}
vector<u64> divisorsFrom(const vector<pair<u64, int>>& f) { // all divisors (unsorted), d(n) of them
vector<u64> ds{1};
for (auto [p, e] : f) { int m = sz(ds); u64 pk = 1; for (int k = 1; k <= e; k++) { pk *= p; for (int i = 0; i < m; i++) ds.push_back(ds[i] * pk); } }
return ds;
}| From | Value |
|---|---|
| number of divisors | |
| sum of divisors | |
| Euler | |
| Carmichael (exponent of ) | , except for |
| perfect square / -th power | all even / divisible by |
| primitive root exists | (Primitive Roots) |
Proof: Miller–Rabin
Write with odd. If is an odd prime, is a field, so has only the roots . By Fermat , and walking the sequence backwards from the final 1, each earlier term is a square root of the next: either the sequence is all ones from the start (), or the term just before the first 1 is . So a prime never produces the “composite” verdict, and any base that does is a certificate of compositeness. For odd composite , at most a quarter of the bases in fail to witness (Rabin–Monier), and the seven bases used here were verified by exhaustive search to have no common strong pseudoprime below ; the trial division by primes handles small and bases divisible by are skipped (they carry no information).
Proof sketch: Pollard's rho runs in about
Let be the smallest prime factor of (). Modulo , the map behaves like a random function, so the sequence repeats modulo after steps (birthday paradox, Probability), i.e. and so . Brent’s cycle finding compares with the following values, which detects any cycle within a constant factor of its length. The gcd is only if the walk also closed modulo every other prime factor at the same moment, which happens with small probability; then a new is drawn. Batching 128 differences into one product loses nothing: if the product’s gcd with is , the block is replayed one step at a time. So a factor appears after expected multiplications (heuristically; no proof for this specific map is known).
Beyond Pollard rho: Baillie–PSW (one Miller–Rabin base-2 test plus a Lucas test, no known counterexample) is a fast primality heuristic; Pollard’s Kangaroo adapts the same random-walk idea to discrete logarithms; Lenstra’s ECM factors numbers with a medium-sized factor (up to ~60 digits) faster than rho; the quadratic sieve / GNFS are what’s needed for genuinely large semiprimes, where rho is hopeless — none of these are typically hand-implemented in a contest, but recognise the names.
Proof: divisor formulas and Korselt
By unique factorisation a divisor is with , giving ; summing, , and each factor is a geometric series. is inclusion–exclusion over the primes dividing (Arithmetic Functions). Korselt (if): for squarefree with , for every coprime to , hence modulo by CRT. (Only if): if , take of order modulo (); would need , impossible as . If , a primitive root modulo (lifted by CRT to be coprime to ) has .
Wilson’s theorem and factorials modulo
iff is prime; for composite , , and . Too slow as a test, but it evaluates products like , and in factorial-mod- problems (Factorials mod p).
Proof: Wilson
For prime , pair each with its inverse; only are self-inverse (), so the product is . For composite with : if both appear in , so ; if with , then and are distinct and , so ; gives . In both composite cases the product is not .
Useful consequences: (drop the factor from Wilson), and more generally a factorial near converts to a small one via — handy when a formula needs for small . holds only for the three known Wilson primes 5, 13, 563 (none other known below ). Defining as the product of integers not divisible by , Wilson gives — the engine behind the generalised Lucas theorem (Factorials mod p).
Special forms worth checking before general factorization
| Form | Approach |
|---|---|
| (perfect power) | check each from 2 to , taking an integer -th root |
| (difference of squares) | Fermat’s method: fast when ‘s two factors are close to , useless otherwise |
strip powers of two with __builtin_ctzll first | |
| factorials and binomials | never factor the number itself — use Legendre’s formula for the exponent of in |