I used std::multiset to determine how many times that factor appears.
I'd like to know if it can be improved; I've focused on the algorithm rather than the code.
https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
std::multiset<std::int64_t> pollards_rho(std::int64_t n)
{
std::multiset<std::int64_t> factors{};
if (n == 0 || n == 1)
{
return factors;
}
if (n < 0)
{
factors.insert(-1);
n = -n;
}
// If n is even, add 2 and get rid of all even factors.
if (n % 2 == 0)
{
factors.insert(2);
while (n % 2 == 0)
{
n /= 2;
}
if (n == 1)
{
return factors;
}
}
// Select an x_0 uniformly at random from [2, n - 1].
// x_0 is chosen as 2 for simplicity.
//
// Floyd's cycle-finding algorithm.
// x => x_i
// y => x_i+1
std::int64_t x{2}, y{x}, d{1};
// f(x_i+1) = x_i^2 + 1 mod n
auto f = [n](const std::int64_t num) noexcept
{
return (num * num + 1) % n;
};
// If we obtain a factor greater than 1, we are done.
while (d == 1)
{
x = f(x);
y = f(f(y));
d = std::gcd(std::abs(x - y), n);
}
/**
* if (d == n)
* {
* return std::nullopt;
* }
* else
* {
* return d;
* }
*/
// The algorithm normally returns either a non-trivial factor d or failure,
// but we need to find all prime factors.
if (d == n)
{
// If d and n are the same, we have a prime number.
factors.insert(n);
}
else
{
// Look for other factors.
factors.merge(pollards_rho(d));
factors.merge(pollards_rho(n / d));
}
return factors;
}