筛选的Eratosthenes越野车实施

时间:2018-04-07 15:08:52

标签: c++

我从c ++开始,我想实施Eratosthenes的筛子。

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>

using namespace std;

vector<unsigned long long int> sieveOfEratosthenes(unsigned long long int min, unsigned long long int max) {
    vector<unsigned long long int> result;

    if (max <= 1) return result;
    if (min < 1) return result;


    if (max == 2) {
        result.push_back(max);
        return result;
    }

    if(min == 1) {
        min = 2; // skip 1 as it is not prime
    }

    bool primes[(max - min)+ 1];
    //Assume all number within range are prime and filter later
    for (unsigned long long int  i = min; i <= max ; i++) {
        primes[i] = true;
    }

    for (unsigned long long int  i = min; i < sqrt(max); i++ ) {
        if(primes[i]) {
            for (unsigned long long int  j = i; i*j <= max; j++) {
                primes[i*j] = false;
            }
        }
    }

    for (unsigned long long int  i = min; i <= max ; i++) {
        if (primes[i]) {
            result.push_back(i);
        }
    }

    return result;

}

void print(vector<unsigned long long int> result) {
    for ( auto &i : result ) {
        cout << i << std::endl;
    }
}

int main() {
    int start_s=clock();
    vector<unsigned long long int> result = sieveOfEratosthenes(1,1000000);
    int stop_s=clock();
    cout << "time: " << (stop_s-start_s)/double(CLOCKS_PER_SEC)*1000 << " ms" << endl;
    print(result);
    return 0;
}

当我为1-100运行时,我得到了正确的结果,但对于1-1000000我得到1000000这也是错误的。

修改

我根据C ++标准重构了代码,并提供了@badola和@Ben Voigt的建议。代码也可以在Github上找到

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <fstream>

using namespace std;
using u_big = unsigned long long int;

vector<u_big> sieveOfEratosthenes(u_big min, u_big max) {
    vector<u_big> result;

    if (max <= 1 || min < 1 ) return result;

    if(min == 1) {
        min = 2; // skip 1 as it is not prime
    }

    if (max == 2) {
        result.push_back(max);
        return result;
    }


    /*
     * Declare a vector of boolean and ser all value to true
     * Consider all numbers to be prime at this point
     */
    vector<bool> primes(min + (max - min) + 1,true);

    auto sqrt_max = (u_big) sqrt(max);

    for (auto i = min; i < sqrt_max; i++ ) {
        if(primes.at(i)) {
            /*
             * Filter out non primes
             * Multiples of positive numbers cannot be primes
             */
            for (auto  j = i; i*j <= max; j++) {
                primes.at(i*j) = false;
            }
        }
    }

    for (auto  i = min; i <= max ; i++) {
        if (primes.at(i)) {
            result.push_back(i);
        }
    }

    return result;

}

void print(vector<u_big> result) {
    for ( auto const &i : result ) {
        cout << i << std::endl;
    }
}

void save(const string &filename,vector<u_big> result) {
    ofstream outFile(filename);
    for (const auto &p : result)  outFile << p << "\n";

}

int main() {
    unsigned long long int min,max;
    cout << "Enter minimum : ";
    cin >> min;
    cout << "\nEnter maximum : ";
    cin >> max;
    int start_s=clock();
    vector<u_big> result = sieveOfEratosthenes(min,max);
    int stop_s=clock();
    cout << "Runtime to generate primes : " << (stop_s-start_s)/double(CLOCKS_PER_SEC)*1000 << " ms" << endl;
    cout << "Number of primes : " <<  result.size() << endl;
    cout << "Primes saved to sieve.txt" << endl;
    save("primes.txt", result);
    //print(result);
    return 0;
}

1 个答案:

答案 0 :(得分:0)

问题是,您正在访问阵列分配的内存之外的索引 您需要将矢量初始化为(max + 1)个位置。

请优先选择std::vector而不是c-style数组并使用at()运算符,只要程序在最大分配索引上运行,程序就会抛出异常。

引发异常:terminating with uncaught exception of type std::out_of_range: vector

我重构了你的代码以适应C ++ 11,因为在你提到的使用基于C ++ 11的编译器的评论中。

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>

using u_big = unsigned long long int; // Whatever you want, please don't type it 
                                      // in multiple locations, too hard to update the code
                                      // Prefer using, from C++11

std::vector<u_big> sieveOfEratosthenes(u_big min, u_big max) {
    std::vector<u_big> result;

    if (max <= 1 || min < 1) return result;

    if (max == 2) {
        result.push_back(max);
        return result;
    }

    if(min == 1) min = 2; // skip 1 as it is not prime

    std::vector<bool> primes(max + 1, true); // set them all to true while creating vector
    // here was the real problem
    // you were actually accessing (max + 1) elements in your array
    // but were requesting for (max - min + 1) elements 

    for (auto i = min; i < sqrt(max); ++i) {
        if(primes.at(i)) { 
        // as suggested in the comments, use at()
        // you would have witnessed  your code throw exception
            for (auto j = i; i*j <= max; ++j) {
                primes.at(i * j) = false;
            }
        }
    }

    for (auto i = min; i <= max; ++i) {
        if (primes.at(i)) {
            result.push_back(i);
        }
    }
    return result;
}

template <typename Iterable>
void print(Iterable const & result) {
    for (auto const & i : result ) { // please use const &, if not modifying
        std::cout << i << ", ";
    }
    std::cout << std::endl;
}

int main() {
    auto start_s = clock();
    auto result = sieveOfEratosthenes(1,1000000);
    //auto result = sieveOfEratosthenes(1,100);
    auto stop_s = clock();
    std::cout << "time: " << (stop_s-start_s)/double(CLOCKS_PER_SEC)*1000 
    << " ms" << std::endl;
    print(result);
    return 0;
}