[英]Fast Prime Factorization Algorithm
我正在用 C 编写一个代码,它返回一个正整数可以表示为两个正整数的完全平方和的次数。
R(n) is the number of couples (x,y) such that x² + y² = n where x, y, n are all
non negative integers.
为了计算 R(n),我需要首先找到 n 的质因数分解。
问题是我已经尝试了很多可以在 C 上使用的素数分解算法,但我需要我的代码尽可能快,所以如果有人能给我他/她认为是计算大到2147483742.
的数的质因数分解的最快算法2147483742.
多么奇怪的限制; 2147483742 = 2^31 + 94。
正如其他人指出的那样,对于一个数字,这个由素数进行的小试除很可能足够快。 如果不是,您可以尝试 Pollard 的 rho 方法:
/* WARNING! UNTESTED CODE! */
long rho(n, c) {
long t = 2;
long h = 2;
long d = 1;
while (d == 1) {
t = (t*t + c) % n;
h = (h*h + c) % n;
h = (h*h + c) % n;
d = gcd(t-h, n); }
if (d == n)
return rho(n, c+1);
return d;
}
称为rho(n,1)
此函数返回n的(可能是复合)因子; 如果您想找到n 的所有因子,请将其放入循环中并重复调用它。 你还需要一个素数检查器; 对于您的极限,以 2、7 和 61 为基数的 Rabin-Miller 测试被证明是准确且相当快的。 您可以在我的博客上阅读更多关于使用质数编程的信息。
但无论如何,鉴于如此小的限制,我认为您最好使用素数试除。 其他任何东西都可能渐近地更快,但实际上更慢。
编辑:这个答案最近收到了几个赞成票,所以我添加了一个简单的程序,用 2、3、5 轮进行轮分解。 该程序称为wheel(n)
,按递增顺序打印n的因子。
long wheel(long n) {
long ws[] = {1,2,2,4,2,4,2,4,6,2,6};
long f = 2; int w = 0;
while (f * f <= n) {
if (n % f == 0) {
printf("%ld\n", f);
n /= f;
} else {
f += ws[w];
w = (w == 10) ? 3 : (w+1);
}
}
printf("%ld\n", n);
return 0;
}
我在 我的博客中讨论了轮子分解; 解释很长,所以我不会在这里重复。 对于适合long
整数,您不太可能显着改善上面给出的wheel
函数。
有一种快速的方法可以减少候选人的数量。 此例程尝试 2,然后是 3,然后是所有不能被 3 整除的奇数。
long mediumFactor(n)
{
if ((n % 2) == 0) return 2;
if ((n % 3) == 0) return 3;
try = 5;
inc = 2;
lim = sqrt(n);
while (try <= lim)
{
if ((n % try) == 0) return try;
try += inc;
inc = 6 - inc; // flip from 2 -> 4 -> 2
}
return 1; // n is prime
}
inc 在 2 和 4 之间的交替经过仔细对齐,以便跳过所有偶数和可被 3 整除的数。对于这种情况: 5 (+2) 7 (+4) 11 (+2) 13 (+4) 17
试验在 sqrt(n) 处停止,因为至少有一个因子必须等于或低于平方根。 (如果两个因子都 > sqrt(n),那么因子的乘积将大于 n。)
尝试次数为 sqrt(m)/3,其中 m 是系列中可能的最高数字。 对于 2147483647 的限制,最坏情况下(对于 2147483647 附近的素数)最多产生 15,448 个除法,包括 2 和 3 测试。
如果数字是合数,则划分的总数通常要少得多,很少会更多; 甚至考虑到重复调用例程来获取所有因素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.