这是我在C中的代码,来自project-Euler的问题#3,我必须找到最大的素数因子600851475143。
#include <stdio.h>
#include <stdlib.h>
bool is_prime(long int number){
long int j;
for (j=2; j<=number/2; j++){
if (number%j==0) return false;
if (j==number/2) return true;
}
}
int main(){
long int input;
scanf("%d", &input);
long int factor;
int ans=0;
for (factor=input/2; factor>1; factor--){
if (input%factor==0 && is_prime(factor)) {
ans = factor;
break;
}
}
printf("%d\n", ans);
system("pause");
return 0;
}
虽然它适用于小数字,但逐渐需要花费越来越多的时间来给出答案。最后,对于600851475143,代码返回0,这显然是错误的。 有人可以帮忙吗? 非常感谢。
答案 0 :(得分:3)
需要考虑的一些事项:
正如@Alex Reynolds指出的那样,你想要考虑的数字可能太大而无法容纳int
。您可能需要使用long
或uint64_t
来存储该号码。仅这一点就可以解决问题。
不是检查每个除数并查看哪些是素数,而是想要尝试这种方法:将n设置为600851475143。对于从2向上的每个整数,尝试将n除以该整数。如果它干净地分开,则从n中除去该数字的所有副本,并将最大素数因子记录为当前整数。如果你仔细想一想,你会发现你用这种方式考虑的唯一除数是素数。作为一个有用的提示 - 如果n没有小于√n的除数(除了1),那么它就是素数。这可能会让你的搜索空间上限比你正在使用的两个技巧更加紧密。
不是将除数增加1,而是尝试将2作为除数测试,然后仅除以奇数(3,5,7,9,11等)。除2之外的偶数不是素数,所以这会将你需要除以的数字减半。
或者,通过从互联网下载素数列表创建一个存储所有素数达√600851475143的文件,然后测试每个素数以查看是否有任何素数除以600851475143并取最大值。 : - )
希望这有帮助!
答案 1 :(得分:2)
我建议你改进代码的primality check部分。你的方法的运行时间是 O(n 2 )所以你应该使用一个更有效的算法,就像众所周知的Miller-Rabin素性测试的 O(KLOG 3 n)的强> 的。 我在这里为您提供伪代码,您可以自己编写代码:
Input: n > 3, an odd integer to be tested for primality; Input: k, a parameter that determines the accuracy of the test Output: composite if n is composite, otherwise probably prime write n − 1 as 2s·d with d odd by factoring powers of 2 from n − 1 WitnessLoop: repeat k times: pick a random integer a in the range [2, n − 2] x ← ad mod n if x = 1 or x = n − 1 then do next WitnessLoop repeat s − 1 times: x ← x2 mod n if x = 1 then return composite if x = n − 1 then do next WitnessLoop return composite return probably prime
我提供link给你看python中的一个实现,它也将你的算法与你的算法进行比较。顺便说一句,这个算法在网络上有很多实现,但我认为自己做对可以帮助你更好地理解它。
答案 2 :(得分:2)
尝试以下代码。它基本上实现了接受答案中的要点。唯一的改进是它使用车轮分解http://en.wikipedia.org/wiki/Wheel_factorization
跳过2,3和5的所有倍数//find largest prime factor for x <2^64
#include <stdio.h>
#include <stdint.h>
int main() {
uint64_t x = 600851475143;
int wheel[] = {4,2,4,2,4,6,2,6};
while(x>2 && x%2==0) x/=2;
while(x>3 && x%3==0) x/=3;
while(x>5 && x%5==0) x/=5;
for(uint64_t j=0, i=7; i<=x/i; i+=wheel[j++], j%=8) {
while(x>i && x%i==0) x/=i;
}
printf("%llu\n", x);
}
可以做的另一件事是预先计算小于2 ^ 32的所有素数(而不是下载它们),然后只划分素数。我知道这样做的最快方法是Sieve of Eratosthenes。这是一个使用OpenMP的版本,它可以在不到一秒的时间内找到高达10亿的素数http://create.stephan-brumme.com/eratosthenes/