筛查多达20亿个对象会导致细分错误

我正在使用此程序检查是否为素数。

使用算法-筛网:

#include<bits/stdc++.h>
//#define _max    2000000001
#define _max    20000001
using namespace std;
bool sieve[_max];
void init()
{
    memset(sieve,true,sizeof(sieve));
    sieve[0]=sieve[1]=false;
    for(int i=2;i<_max;i+=2)
    {
        sieve[i]=false;
    }
}
void go_sieve(int n)
{
    n++;
    for(int i=3;i<n;i+=2)
    {
        if(sieve[i]==false)
            continue;
        for(int j=2*i;j<n;j+=i)
            sieve[j]=false;
    }
}
void print(int n)
{
    n++;
    printf("-------------\n");
    for(int i=0;i<n;i++)
    {
        if(sieve[i])
            cout << i << " ";
    }
    printf("\n-------------\n");
}
int main()
{
    init();
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int x;
        scanf("%d",&x);
        go_sieve(x);
        //print(x);
        if(sieve[x])
            printf("Prime\n");
        else
            printf("Not prime\n");
    }
    return 0;
}

现在它可以在2e7上正常运行,但是我想检查到2e9,如果我将_max更改为2000000001,它会给我{{1} },并退出并显示错误代码。

如何解决此问题?

我用set尝试了一种新方法:

segmentation error

目标是在512MB〜1GB内存中执行它。

king1302218 回答:筛查多达20亿个对象会导致细分错误

我无法在系统上重现此内容。我的猜测是,这与系统相关的限制有关。

您将sieve声明为全局数组(静态存储持续时间),并且该数组很大(即2000000001 * sizeof(bool)-可能是2-8G,具体取决于bool的size)。也许您的系统无法处理这个问题。

而不是全局数组,请尝试使用动态分配:

// bool sieve[_max]; comment out this
bool* sieve = NULL;

...
...

int main()
{
    sieve = (bool*)malloc(_max * sizeof *sieve);
    if (sieve == NULL)
    {
        // out of memory
        exit(1);
    }

    ...

说:

您的代码是C ++,但是您的风格更像C。

在C ++中,您可能会改用std::vector。这将使一切变得容易得多。

顺便说一句:也请避免使用全局变量。而是在main中定义向量(或动态数组),并将其按引用传递给函数。

,

您可能会达到系统上的某些内存限制,从而导致分段错误。

但是,您不需要这么大的数组。使用Eratosthenes筛网,您需要计算直至x的数字。您可以使用std::vector来代替数组,并在计算更多数字时增加其大小。这应该可以让您计算一些数字,但是如果数字较大,您将再次达到内存限制。

您还可以使用某些算法,该算法要求您存储较少的数字。要确定x是否为质数,只需要与小于x平方根的质数进行比较。您不必存储非质数的数字。使用x = 1e10,您只需要存储5e8 numbers

下面是一些带有向量的示例(可能不是最优的):

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

std::vector<int> primes = {2};

void calculate(int x) {
    const int largest_prime = primes.back();
    if (largest_prime >= x) {
        // Already calculated
        return; 
    }
    for (size_t i = largest_prime + 1; i <= x; i++) {
        bool not_prime = false;
        for (size_t j = 0; j < primes.size(); j++) {
            if (i % primes[j] == 0) {
                not_prime = true;
                break;
            }
        }
        if (!not_prime) {
            primes.push_back(i);
        }
    }
}

bool check(int x) {
    calculate(x);
    return std::find(primes.begin(),primes.end(),x) != primes.end();
}

int main() {
    std::cout << check(15) << std::endl;
    std::cout << check(256699) << std::endl;
}
,

如果要枚举较大范围的质数,则应使用segmented Sieve of Eratosthenes;它将更快(由于缓存效果)并且使用更少的内存。

如果您只想确定一个数字是质数还是几个数字,那么筛分是一种可怕的方法。仅当您对整个数字范围感兴趣时才应使用筛分。对于 n (最多十亿),审判部门很简单,而且可能足够快。对于更大的数字,使用Miller-Rabin检验或Baillie-Wagstaff检验可能更好。

本文链接:https://www.f2er.com/3060249.html

大家都在问