Skip to main content

Cycle Detection in Iterated Function Values

Theory

Floyd's algorithm

Floyd's algorithm (also called tortoise and hare algorithm) only accesses the sequence by storing and copying pointers, function evaluations, and equality tests; therefore, it qualifies as a pointer algorithm. It uses operations of these types, and storage space.

Brent's algorithm

Brent's algorithm is also a pointer algorithm that uses tests and function evaluations and storage space. It has two advantages compared to the Floyd's algorithm: it finds the correct length of the cycle directly, rather than needing to search for it in a subsequent stage, and its steps involve only one evaluation of rather than three. The number of function evaluations can never be higher than for Floyd's algorithm. Brent claims that, on average, his cycle finding algorithm runs around more quickly than Floyd's and that it speeds up the Pollard's rho algorithm by around .

Code

#include <functional>

namespace CycleDetection {
std::tuple<int, int> floyd(int start, std::function<int (int)> f) {
int a = f(start), b = f(a);
while (a != b) { a = f(a); b = f(f(b)); }

int mu = 0;
a = start;
while (a != b) { a = f(a); b = f(b); ++mu; }

int lambda = 0;
do { b = f(b); ++lambda; } while (a != b);

return {lambda, mu};
}

std::tuple<int, int> brent(int start, std::function<int (int)> f) {
int lambda = 1, power = 1;
int a = start, b = f(a);
while (a != b) {
if (lambda == power) { a = b; power *= 2; lambda = 0; }
b = f(b); ++lambda;
}

a = b = start;
for (int i = 0; i < lambda; ++i) b = f(b);

int mu = 0;
while (a != b) { a = f(a); b = f(b); ++mu; }

return {lambda, mu};
}
}

#include <iostream>

int f(int x) {
if (x == 10) return 3;
return x + 1;
}

int main() {
auto [x, y] = CycleDetection::brent(0, f);
std::cout << x << ' ' << y << '\n';
}