繁体   English   中英

为什么我的程序不能大量使用?

[英]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 longunsigned 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM