Purpose: Find a non-trivial factor of a composite in expected time — enough to fully factor any 64-bit integer in microseconds.

Algorithm

  1. If is even, return 2. If is prime (Miller-Rabin), it has no non-trivial factor.
  2. Pick a pseudo-random map with random .
  3. Iterate two pointers, (slow) and (fast, two steps per round) — a Floyd cycle detection walk.
  4. At each step compute .
    • factor found.
    • → the walk collapsed; restart with a new .
  5. 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

__gcd dominates 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