Eratosthenes筛选大量c ++

时间:2015-01-20 19:30:38

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

就像这个question一样,我也正在研究Eratosthenes的筛子。同样来自"编程原理和使用c ++" 的练习,第4章。我能够正确地实现它,它的功能正如练习所要求的那样。

#include <iostream>
#include <vector>

using namespace std;

int main() {
    unsigned int amount = 0;

    cin >> amount;

    vector<int>numbers;

    for (unsigned int i = 0; i <= amount; i++) {
        numbers.push_back(i);
    }

    for (unsigned int p = 2; p < amount; p++) {
        if (numbers[p] == 0)
            continue;

        cout << p << '\n';

        for (unsigned int i = p + p; i <= amount; i += p) {
            numbers[i] = false;
        }
    }

    return 0;
}

现在,我如何处理amount输入中的真实大数字? unsigned int类型应该允许我输入2 ^ 32 = 4,294,967,296的数字。但我不能,我的内存不足。是的,我已经完成了数学计算:存储2 ^ 32个int,每个32位。所以32/8 * 2 ^ 32 = 16 GiB的内存。我只有4个GiB ......

所以我在这里真正做的是将非素数设置为零。所以我可以使用布尔值。但是,它们仍然需要8位,每个1位。理论上我可以使用我的一些交换空间用于操作系统和开销来达到unsigned int(8/8 * 2 ^ 32 = 4 GiB)的限制。但是我有一台x86_64 PC,那么大于2 ^ 32的数字呢?

知道素数是important in cryptography,必须有一种更有效的方法吗?是否还有方法来优化找到所有这些素数所需的时间?

2 个答案:

答案 0 :(得分:5)

从存储的角度来说,您可以使用std::vector<bool>容器。由于它的工作原理,您必须以speed进行交易才能进行存储。因为每个布尔值实现一位,所以您的存储效率提高了8倍。如果你有可用于这个程序的所有RAM,你应该可以获得接近8 * 4,294,967,296的数字。您唯一需要做的就是使用unsigned long long来释放64位数字的可用性。

注意:使用下面的代码示例测试程序, amount 输入为80亿,导致程序运行时的内存使用量约为。 975 MiB,证明理论数字。

您还可以获得一些时间,因为您可以立即声明完整的向量,而无需迭代:vector<bool>numbers (amount, true);创建 size 的向量,等于输入 amount ,将所有元素设置为true。现在,您可以调整代码以将非素数设置为 false 而不是0。

此外,一旦您按直到金额的平方根,所有保留 true 的数字都是素数。在输出素数后立即插入if (p * p >= amount)作为额外的继续条件。这对您的处理时间也是一个微不足道的改进。

修改:在最后一个循环中,p可以被平方,因为直到p的平方的所有数字都已被证明不是之前数字的素数。< / p>

总之,你应该得到这样的东西:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    unsigned long long amount = 0;

    cin >> amount;

    vector<bool>numbers (amount, true);

    for (unsigned long long p = 2; p < amount; p++) {
        if ( ! numbers[p])
            continue;

        cout << p << '\n';

        if (p * p >= amount)
            continue;

        for (unsigned long long i = p * p; i <= amount; i += p) {
            numbers[i] = false;
        }
    }

    return 0;
}

答案 1 :(得分:1)

您已经提出了几个不同的问题。

对于最高2 ** 32的素数,筛选是合适的,但您需要分段而不是在一个大博客中工作。我的回答here说明了如何做到这一点。

对于非常大的加密素数,过程是选择一个数字,然后使用概率测试(例如Miller-Rabin测试或Baillie-Wagstaff测试)测试它的素数。这个过程并不完美,有时可能会选择复合而不是素数,但这种情况非常罕见。