我在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.
答案 0 :(得分:10)
多么奇怪的限制; 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测试被证明是准确且合理的快速。您可以在my blog了解有关素数编程的更多信息。
但无论如何,考虑到这么小的限制,我认为你最好不要使用试验分组。其他任何东西都可能渐近更快,但实际上更慢。
编辑:这个答案已收到几个最近的赞成票,所以我添加了一个简单的程序wheel factorization用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;
}
我在my blog处讨论车轮分解;解释很冗长,所以我在此不再重复。对于适合long
的整数,您不太可能明显改善上面给出的wheel
函数。
答案 1 :(得分:0)
有一种减少候选人数量的快捷方法。此例程尝试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
}
2和4之间的inc的交替是仔细对齐的,以便它跳过所有偶数和可被3整除的数字。对于这种情况:5(+2)7(+4)11(+2)13(+4 )17
试验在sqrt(n)处停止,因为至少有一个因子必须等于或低于平方根。 (如果两个因子都是&gt; sqrt(n)那么因子的乘积将大于n。)
尝试次数为sqrt(m)/ 3,其中m是系列中可能的最高编号。对于2147483647的限制,最大情况下产生最多15,448个分区(对于2147483647附近的素数),包括2和3个测试。
如果数字是复合数,则总分数通常要少得多,而且很少会更多;甚至考虑到反复调用例程以获得所有因素。