优化Eratosthenes的筛选

时间:2017-10-16 16:20:39

标签: c++ algorithm optimization sieve-of-eratosthenes

我目前正在努力进一步优化我的筛子。我必须使用eratosthenes的筛子计算两个数字之间的素数,我知道需要工作的两个数字是2000000000000和2000000100000.我的当前代码由于运行时间太长而得到分段错误。任何有关优化的帮助都将非常感激:

#include <iostream>
#include <cmath>
using namespace std;

double Sieve(long long a, long long b){

    //Create array of type bool
    bool *prime;
    prime = new bool[b];

    //Set all values in array to true
    for (long i = 0; i < b; i++){
        prime[i] = true;
    }


    long count = 0;

    //Runs through main Sieve algorithm
    for (long x = 2*2; x <= (b); x += 2 ){
        prime[x] = false;
    }
    for (long x = 3; x <= sqrt(b); x = 2*x ){
        if (prime[x] == true){
            for (long y = pow(x,2); y <= b; y += x){
                prime[y] = false;
            }
        }

    }

    //Loop to print out and count how many primes are present
    for (long x = a; x <= b; x++){
        if(prime[x] == true){
            count++;
        }
    }
    return count;
}

int main(){
    int a, b;
    cout << "Please enter two numbers separated by one space" << endl;
    cin >> a >> b;
    cout << Sieve(1,20) << endl;
    cout << Sieve(a,b) << endl;
}

3 个答案:

答案 0 :(得分:2)

您正在尝试分配 way 过多的内存,而new可能会失败并抛出std::bad_alloc exception。如果您没有注意,未捕获的异常可能类似于分段错误。

要解决此问题,您需要两个数组 - 一个用于输出范围大小为100001,另一个用于确定素数直到sqrt(b)。

正如另一个答案所指出的那样,使用std::vector<bool>也会将你的内存需求减少8个。不足以取消需要两个数组,但仍然有很大的帮助。有时候人们会反对vector<bool>,因为它有一些奇怪之处,但为了这个目的,它是完美的。

答案 1 :(得分:0)

您的内存可能不足。使用bool数组可能为每个条目分配1byte,如果允许使用std::vector,则std::vector<bool>仅使用一个位。

答案 2 :(得分:0)

2000000000000,对于数组而言太大。而是使用位集。您可以以更快的方式生成更大的素数。以这种方式声明全局范围中的位集,使其可以容纳10 ^ 7。但是您可以使用分段筛算法使它适用于2000000000000。在这种情况下,sqrt(2000000000000)=1414213。这就是为什么您必须生成2到1414214之间的所有质数的原因。然后使用分段筛算法

#include <bits/stdc++.h>
#define bitset_range 1414214
typedef long long int lli;
typedef long int li;
using namespace std;
template <typename T>
void printer(T a) {
    cout << a << endl;
}
vector<li> stock_prime;
bitset<bitset_range + 1> numbers;
int main() {
    lli start, stop;
    //normal seieve
    numbers.set();
    numbers.reset(0);
    numbers.reset(1);
    for (li i = 2; i <= bitset_range; i++) {
        if (numbers.test(i)) {
            for (li j = i * i; j <= bitset_range; j+= i) {
                numbers.reset(j);
            }
            stock_prime.push_back(i);
        }
    }
    //for_each(stock_prime.begin(), stock_prime.end(), printer<int>);
    cout << "Size: " << stock_prime.size() << endl;

    //now use segmented seive algorithm here remember to use bitset rather than bool array



    return 0;
}