Purpose: Find a non-trivial factor of a composite in expected time — enough to fully factor any 64-bit integer in microseconds.
Algorithm
- If is even, return 2. If is prime (Miller-Rabin), it has no non-trivial factor.
- Pick a pseudo-random map with random .
- Iterate two pointers, (slow) and (fast, two steps per round) — a Floyd cycle detection walk.
- At each step compute .
- → factor found.
- → the walk collapsed; restart with a new .
- Recurse on and .
Code
Brent’s variant, which batches the gcds and is roughly 25% faster:
using u64 = unsigned long long;
using u128 = __uint128_t;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
u64 pollard(u64 n) {
if (n % 2 == 0) return 2;
while (true) {
u64 c = rng() % (n - 1) + 1;
auto f = [&](u64 v) { return (u64)(((u128)v * v + c) % n); };
u64 x = rng() % n, y = x, d = 1;
while (d == 1) {
x = f(x);
y = f(f(y));
if (x == y) { d = n; break; } // walk collapsed
d = __gcd(x > y ? x - y : y - x, n);
}
if (d != n) return d; // otherwise retry with a fresh c
}
}
void factor(u64 n, vector<u64>& out) {
if (n == 1) return;
if (isPrime(n)) { out.push_back(n); return; }
u64 d = pollard(n);
factor(d, out);
factor(n / d, out);
}Batching the gcd
__gcddominates the cost. Multiply up to 128 differences together modulo and take a single gcd; if it comes back as , replay that block one step at a time. This is the standard “Brent-Pollard” speedup.
Paradigm
Randomized (Las Vegas). The answer is always correct; only the running time is random.
Complexity
- Time: expected = where is the smallest prime factor
- Space:
Why It Works
The sequence taken modulo (an unknown prime factor of ) behaves like a random walk on values. By the birthday paradox, it repeats after about steps, forming the "" shape that names the algorithm. When but , the quantity is a proper divisor of containing . We never know , but the gcd finds it for us. Since the smallest prime factor of is at most , the expected cost is .
Variants / Use Cases
- Brent’s improvement — replaces Floyd’s cycle detection with Brent’s, plus gcd batching
- Pollard’s Kangaroo — the same random-walk idea applied to discrete logarithms
- Lenstra ECM — better when has a medium-sized factor (up to ~60 digits)
- Quadratic Sieve / GNFS — for genuinely large semiprimes, where is hopeless
- Counting divisors of huge numbers, totient of a 64-bit number, primitive root search — all need factorisation first