为什么我的程序无法使用大数字?

时间:2016-09-10 19:18:07

标签: c++

我正在尝试编写一个找到最大素数因子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; 
}

3 个答案:

答案 0 :(得分:1)

@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位置计算更昂贵。

我通过这种方式解决150212868857素数的OP任务的时间是我的1.4GHz AMD上的约7:05分钟:

150212868857

real    7m5.156s
user    7m5.063s
sys 0m0.008s

记住所有以前找到的素数以加速isPrime()测试的尝试更糟糕,所以我没有给它机会完成。这解释了通过遍历素数向量的相同必要性,并且由于要从内存中读取的数据量,它甚至更加昂贵。

最终变体只是候选除数的迭代,范围从3到num,步骤2仅在isPrime为候选时才调用num。此方法显示与前一个加减几秒相同的时间。因此,只要数学运算适合现代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

答案 1 :(得分:0)

600851475143是非常大号,您的算法非常效率低下。我怀疑它最终会终止,但“最终”远远超出你愿意等待的时间。

以上假设您的平台上的long long甚至能够表示数字 - 如果它只是32位,那么它就不是。

你真正需要的是一种更有效的算法。

答案 2 :(得分:0)

您的程序失败,因为您使用的是int数据类型。它有32 bits, i.e 2^32 ~= 9 digits max

要访问大于9位的某些值,请尝试使用long longunsigned long long。它有64 bits, i.e 2^64 ~= 18 digits for signed and 20 digits for unsigned

编辑:^这适用于C ++ 98(Orwell Dev C ++:已测试)

vector<int> pfactor;

这个int on vector使你的程序失败。除非你正在处理2d向量,否则你不需要在向量中保留任何空间,除非你正在使用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;
}