为什么我的程序不能处理大数

Why does my program not work with large numbers?

本文关键字:处理 不能 我的 程序 为什么      更新时间:2023-10-16

我正在试着写一个程序,找到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 - franisfabre提供的答案都不正确。巧合的是,600851475143是71,839,1471和6857的乘积,并且所有因数都小于根号(num)。如果OP中的数字是600851475149(质数)怎么办?

因此,我们需要搜索整个范围[2,num],而不是范围[2,sqrt(num)]。

所以,这是我在几次尝试后得到的结果,我使用Eratosthenes算法的Sieve来优化搜索,以预先计算素数标志的向量并记忆先前发现的素数。

虽然埃拉托色尼筛法是在特定范围内找到所有质数的最快方法(它没有除法运算,只有比除法快几倍的乘法运算),这种方法没有多大帮助,因为它不能消除循环遍行向量以查找标记为素数的元素,然后将问题中的数字与找到的素数相除的需要(我故意在@ jean - franisfabre的实现中将vector<bool>替换为vector<char>,以避免vector<bool>可能的"位打包"实现,因为在矢量计算中的位位置肯定比字符位置计算更昂贵)。

在我的1.4GHz AMD上,我用这种方法解决OP中150212868857 prime的任务的时间是~7:05分钟:

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

试图记住所有以前找到的质数来加速isPrime()测试是更糟糕的,所以我没有给它完成的机会。这可以解释为同样需要遍历质数向量,并且由于需要从内存中读取大量数据,因此成本更高。

最后一个变体只是在步骤2中迭代候选除数3到num的范围,并且只在num为偶数时调用isPrime。这种方法显示了与之前相同的时间正负几秒。因此,只要所使用的数学方法符合现代CPU的本机寄存器,对vector元素的访问就显得和除法一样昂贵。

然而,当所讨论的数字不是素数时(如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中包含number的结果:

$ 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, 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++: testing)

vector<int> pfactor;

int on vector会导致程序失败。你不需要在矢量中保留任何空间,因为它是动态的,除非你在二维矢量上工作。

示例代码:

#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;
}