繁体   English   中英

Eratosthenes筛用于大量C ++

[英]Sieve of Eratosthenes for large numbers c++

就像这个问题一样 ,我也在研究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的数字呢?

知道素数在密码学中重要 ,因此必须有一种更有效的方法吗? 还有其他方法可以优化找到所有这些素数所需的时间吗?

在存储方面,您可以使用std::vector<bool>容器。 由于它的工作方式,您必须牺牲存储速度 因为此实现每个布尔值一位,所以存储效率提高了8倍。 如果您有足够的RAM用于该程序,则应该有可能获得接近8 * 4,294,967,296的数字。 您唯一需要做的就是使用unsigned long long释放64位数字的可用性。

注意 :使用下面的代码示例测试该程序,输入的金额为80亿,导致该程序在运行时的内存使用量大约为80。 975 MiB,证明了理论值。

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

此外,一旦遵循筛子直到数量的平方根,所有保持为真的数字都是质数。 在输出素数之后,插入if (p * p >= amount)作为其他继续条件。 同样,这对于您的处理时间来说是微不足道的改进。

编辑 :在最后一个循环中,可以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;
}

您问了几个不同的问题。

对于不超过2 ** 32的素数,筛分是适当的,但是您需要分段操作而不是在一个大博客中工作。 在这里的答案告诉您如何执行此操作。

对于非常大的密码素数,过程是选择一个数字,然后使用诸如Miller-Rabin检验或Baillie-Wagstaff检验之类的概率检验来测试其素数。 这个过程并不完美,有时可能会选择复合词而不是素词,但是这种情况很少见。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM