[英]Why does my program not work with large numbers?
我正在尝试编写一个找到最大素数600851475143的程序。它与较小的数字(直到10000)完美配合,但仅此而已。 我该如何更改? 该程序不会给出任何错误或结束自身,而只会输出任何内容。
#include <iostream>
#include <vector>
using namespace std;
bool isPrime( unsigned long long int num);
int main() {
unsigned long long int m = 600851475143;
std::vector<int> pfactors;
pfactors.reserve(100000000);
for (long long int i = 2; i <= m; i++) {
if (isPrime(i) == true) {
if (m % i == 0) {
pfactors.push_back(i);
}
}
}
for (vector<int>::iterator it = pfactors.begin(); it != pfactors.end(); it++) {
cout << *it << endl;
}
cin.get();
return 0;
}
bool isPrime(unsigned long long int num)
{
if (num < 2)
return false;
if (num > 2 && (num % 2) == 0)
return false;
for (unsigned long long int i = 2; i < num; i++)
{
if ((num % i) == 0)
{
return false;
}
}
return true;
}
@DanyalImran和@Jean-FrançoisFabre提供的答案都是错误的。 碰巧的是,600851475143是71、839、1471和6857的乘积,所有除数都小于sqrt(num)。 如果OP中的数字为60085147514 9 (质数)怎么办?
因此,我们需要搜索整个范围[2,num],而不是范围[2,sqrt(num)]。
因此,这是我经过几次尝试,使用Eratosthenes算法的Sieve预先计算素数标记的向量并存储先前找到的素数来优化搜索的结果。
尽管Eratosthenes筛网确实是找到某个指定范围内所有质数的最快方法(它没有除法运算,只有比除法快倍数的乘法),但是这种方法无济于事,因为它不能消除对遍历向量以查找标记为素数的元素,然后将所讨论的数除以找到的素数(我在@Jean-FrançoisFabre的实现中故意将vector<bool>
替换为vector<char>
,以避免可能的“位压缩”实现在向量计算中将vector<bool>
用作位位置肯定比char位置计算贵。
在我的1.4GHz AMD上,以这种方式解决OP中针对150212868857 prime的任务的时间大约是7:05分钟:
150212868857
real 7m5.156s
user 7m5.063s
sys 0m0.008s
记忆所有先前发现的质数以加速isPrime()
测试的尝试更加糟糕,因此我没有给它一个完成的机会。 这解释了通过质数向量进行迭代的相同必要性,并且由于要从内存读取的数据量更大,因此代价甚至更高。
最终的变体只是候选除数在3到num
的迭代(步骤2),并且仅当num
与候选偶数isPrime
时才调用isPrime
。 这种方法显示的时间与之前的正负几秒钟相同。 因此,一旦所使用的数学运算适合现代CPU的本机寄存器,对向量元素的访问就好像除法一样昂贵。
但是,当所讨论的数字不是素数时(如在OP中),仍然存在优化的地方,可以缩短搜索时间。
编码:
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
//#define SIEVE
vector<char> primeFlagger;
void initSieve(unsigned long long int limit) {
unsigned long long int root = (unsigned long long int)(sqrt(limit));
primeFlagger = vector<char>(root+1,true);
primeFlagger[0] = primeFlagger[1] = false;
for(unsigned long long int j=2; j<=root; j++)
{
if(primeFlagger[j])
{
for(unsigned long long int k=j; (k*j)<=root; k++)
{
primeFlagger[j*k]=false;
}
}
}
}
#ifdef SIEVE
bool isPrime(unsigned long long int num)
{
if (num <= 2)
return true;
if ((num % 2) == 0)
return false;
unsigned sqr = (unsigned)sqrt(num);
for(unsigned i = 3; i <= sqr; i+=2) {
if (primeFlagger[i] && num % i == 0)
return false;
}
return true;
}
#else
bool isPrime(unsigned long long int num)
{
if (num <= 2)
return true;
if ((num % 2) == 0)
return false;
unsigned sqr = (unsigned)sqrt(num);
for(unsigned i = 3; i <= sqr; i+=2) {
if (num % i == 0)
return false;
}
return true;
}
#endif
int main() {
unsigned long long int m = 600851475143;//150212868857;//600851475149;
std::vector<unsigned long long int> pfactors;
#ifdef SIEVE
initSieve(m);
#endif
if (m % 2 == 0) {
do {
m /= 2;
} while (m % 2 == 0);
pfactors.push_back(2);
}
for (long long int i = 3; i <= m; i+=2) {
if (m % i == 0 && isPrime(i)) {
do {
m /= i;
} while (m % i == 0);
pfactors.push_back(i);
}
}
for (vector<unsigned long long int>::iterator it = pfactors.begin(); it != pfactors.end(); it++) {
cout << *it << endl;
}
return 0;
}
在OP中带有数字的结果:
$ g++ -O3 prime1.cpp
$ time ./a.out
71
839
1471
6857
real 0m0.004s
user 0m0.002s
sys 0m0.002s
600851475143是一个很大的数字,你的算法是非常低效的。 我怀疑它最终会终止,但是“最终”远远超出了您愿意等待的时间。
上面的假设是您平台上的long long
甚至可以表示该数字-如果只有32位,则不是。
您真正需要的是效率更高的算法。
您的程序失败,因为您使用的是int
数据类型。 它具有32 bits, ie 2^32 ~= 9 digits max
要访问一些大于9位的值,请尝试使用long long
或unsigned long long
。 它有64 bits, ie 2^64 ~= 18 digits for signed and 20 digits for unsigned
。
编辑:^这是为C ++ 98(Orwell Dev C ++:已测试)
vector<int> pfactor;
这种对向量的干扰使您的程序失败。 而且,除非您正在处理2D向量,否则由于向量是动态的,因此无需保留任何空间。
示例代码:
#include<math.h>
#include<iostream>
using namespace std;
bool ifPrime ( int number ) {
for ( long long int i=2; i<sqrt(number); ++i ) {
if ( number%i == 0 ) return false;
}
return true;
}
int main ( ) {
long long int number = 600851475143;
static long long int largestPrime;
bool found = false;
for ( long long int i=sqrt(number); i>=0 && !found; i=i-1 ) {
if ( number%i==0 && ifPrime(i) ) {
largestPrime = i;
found = true;
}
}
cout << "Largest Prime for " << number << " is: " << largestPrime << endl;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.