Eratosthenes算法的筛子不适用于大范围

时间:2013-03-03 18:52:43

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

我已经在C ++中编写了一个Eratosthenes算法的筛子,它适用于我测试过的较小数字。但是,当我使用大数字,即2 000 000作为上限时,程序开始给出错误的答案。谁能澄清为什么?

感谢您的帮助。

#include <iostream>
#include <time.h>
using namespace std;

int main() {
    clock_t a, b;
    a = clock();

    int n = 0, k = 2000000; // n = Sum of primes, k = Upper limit
    bool r[k - 2]; // r = All numbers below k and above 1 (if true, it has been marked as a non-prime)
    for(int i = 0; i < k - 2; i++) // Check all numbers
        if(!r[i]) { // If it hasn't been marked as a non-prime yet ...
            n += i + 2; // Add the prime to the total sum (+2 because of the shift - index 0 is 2, index 1 is 3, etc.)
            for(int j = 2 * i + 2; j < k - 2; j += i + 2) // Go through all multiples of the prime under the limit
                r[j] = true; // Mark the multiple as a non-prime
        }

    b = clock();
    cout << "Final Result: " << n << endl;
    cout << b - a << "ms runtime achieved." << endl;
    return 0;
}
编辑:我刚刚进行了一些调试,发现它可以在400左右的极限下运行。然而,在500,它是关闭的 - 它应该是21536,但是是21499

编辑2:啊,我发现了两个错误,似乎已经解决了这个问题。

第一个是由其他人回答的,并且n是溢出的 - 当它成为一个很长的数据类型时,它已经开始工作了。

第二个,也就是值得称赞的错误,是r中的布尔值必须初始化。在检查素数之前运行循环以使它们全部为假,得到了正确的答案。有谁知道为什么会这样?

1 个答案:

答案 0 :(得分:2)

你只是得到一个整数溢出。 C ++类型int具有有限的范围(在32位系统上通常从 - (2 ^ 32)/ 2到2 ^ 32/2 - 1,这通常的最大值是2147483647(特定的最大值您的设置可以通过#include <limits>标头并评估std::numeric_limits<int>::max()找到。即使k小于最大值,您的代码迟早会导致表达式n += i + 2溢出或int j = 2 * i + 2

您必须选择更好(读取:更合适)的类型,例如unsigned,它不支持负数,因此可以表示两倍于int的数字。您也可以尝试unsigned long甚至unsigned long long

另请注意,可变长度数组(VLA;那就是bool r[k - 2])不是标准C ++。您可能希望使用std::vector代替。您也没有将数组初始化为falsestd::vector会自动执行此操作),这也可能是问题所在,尤其是如果您说即使在k = 500时它也不起作用。

在C ++中,您还应该使用<ctime>而不是<time.h>(然后使用clock_tand clock()are defined in the std namespace, but since you are namespace std`,这对你没什么影响),但这或多或少是风格问题。

我在“代码存档”中找到了一个工作示例。虽然它不是基于您的,但您可能会发现它很有用:

#include <vector>
#include <iostream>

int main()
{
    typedef std::vector<bool> marked_t;
    typedef marked_t::size_type number_t; // The type used for indexing marked_t.

    const number_t max = 500;

    static const number_t iDif = 2; // Account for the numbers 1 and 2.
    marked_t marked(max - iDif);
    number_t i = iDif;

    while (i*i <= max) {
        while (marked[i - iDif] == true)
            ++i;
        for (number_t fac = iDif; i * fac < max; ++fac)
            marked[i * fac - iDif] = true;
        ++i;
    }

    for (marked_t::size_type i = 0; i < marked.size(); ++i) {
        if (!marked[i])
            std::cout << i + iDif << ',';
    }
}