以下是我对Pollard的rho算法进行素数分解的实现:
#include <vector>
#include <queue>
#include <gmpxx.h>
// Interface to the GMP random number functions.
gmp_randclass rng(gmp_randinit_default);
// Returns a divisor of N using Pollard's rho method.
mpz_class getDivisor(const mpz_class &N)
{
mpz_class c = rng.get_z_range(N);
mpz_class x = rng.get_z_range(N);
mpz_class y = x;
mpz_class d = 1;
mpz_class z;
while (d == 1) {
x = (x*x + c) % N;
y = (y*y + c) % N;
y = (y*y + c) % N;
z = x - y;
mpz_gcd(d.get_mpz_t(), z.get_mpz_t(), N.get_mpz_t());
}
return d;
}
// Adds the prime factors of N to the given vector.
void factor(const mpz_class &N, std::vector<mpz_class> &factors)
{
std::queue<mpz_class> to_factor;
to_factor.push(N);
while (!to_factor.empty()) {
mpz_class n = to_factor.front();
to_factor.pop();
if (n == 1) {
continue; // Trivial factor.
} else if (mpz_probab_prime_p(n.get_mpz_t(), 5)) {
// n is a prime.
factors.push_back(n);
} else {
// n is a composite, so push its factors on the queue.
mpz_class d = getDivisor(n);
to_factor.push(d);
to_factor.push(n/d);
}
}
}
它基本上是pseudocode on Wikipedia的直接翻译,并依赖于GMP用于大数字和素性测试。实现效果很好,可以考虑诸如
之类的素数1000036317378699858851366323 = 1000014599 * 1000003357 * 1000018361
但会窒息,例如
1000000000002322140000000048599822299 = 1000000000002301019 * 1000000000000021121
我的问题是:除了切换到更复杂的分解算法(例如Quadratic sieve)之外,我能做些什么来改善这一点?
我知道一个改进可能是首先通过预先计算的素数进行一些试验划分,但这对于上述几个大素数的产品没有帮助。
我对改进基本的Pollard's rho方法的任何提示感兴趣,以使其能够处理仅有少数主要因素的大型复合材料。当然,如果您在上面的代码中发现任何愚蠢行为,我也会对这些行为感兴趣。
完全披露:这是一项家庭作业,所以一般提示和指针比完全编码的解决方案更好。通过这种非常简单的方法,我已经获得了作业的及格分数,但当然希望改进。
提前致谢。
答案 0 :(得分:3)
由于Pollard,您使用的是原始版本的rho算法。布伦特的变体做了两项改进:弗洛伊德的乌龟和野兔循环寻找算法被布伦特开发的循环寻找算法所取代,并且gcd计算被延迟,所以它通过循环每百次执行一次而不是每次。但是这些变化只会有一点点改进,可能只有25%左右,而且不会让你考虑你所说的大数字。因此,您需要一个更好的算法:SQUFOF可能适用于您提到的大小的素数,或者您可以实现二次筛或椭圆曲线方法。我在my blog讨论并实施了所有这些算法。