【问题标题】:Why is using all numbers to test for a prime number faster than using prime numbers only为什么使用所有数字来测试素数比只使用素数更快
【发布时间】:2020-03-20 01:12:40
【问题描述】:

我制作了这个程序来生成素数。我知道有很多公式可以将它们的生成速度提高 100 倍,但这就是我所做的。

  1. 我尝试将 i 与 i 下的所有数字相除。那是最简单的方法,但我认为它效率低下,因为除以 2 后,您不需要除以 4 等等。

  2. 我制作了一个小于i 的素数列表,并将i 除以该列表的数字。我使用std::iterator 浏览了列表,因为我看到它被用于所有stackoverflow 答案和其他教程。结果速度慢了很多。就像它花了 22 秒而不是 2 秒。

  3. 我尝试使用 int 遍历列表,但又花了 2 秒。

接下来,我用 1 000 000 来查看方法 1 和 3 之间的区别。令我惊讶的是,方法 1 更快。这是为什么?不应该只使用素数来测试比使用所有数字更快吗?

#include <iostream>
#include <vector>
#include <chrono>

int main()
{
    std::cout << "how high do you want to generate prime numbers? ";
    int x;
    // typed 1 000 000
    std::cin >> x;
    auto starttime = std::chrono::high_resolution_clock::now();
    std::vector<unsigned int> primes;
    bool isPrime;
    for (int i = 2; i <= x; ++i) {
        isPrime = true;

        // takes 293 seconds
        //for (int div{ 2 }; div < i; ++div) {
            //  if ((i % div) == 0) {

        // takes really really long
        //for (std::vector<unsigned int>::iterator div = primes.begin(); div != primes.end(); ++div) {
            //if ((i % *div) == 0) {

        // takes 356 seconds
        for (int iter = 0; iter < primes.size(); ++iter) {
            if ((i % primes[iter]) == 0) {

                isPrime = false;
                break;
            }
        }
        if (isPrime) {
            primes.push_back(i);
            std::cout << i << " ";
        }
    }
    std::cout << "generating prime numbers up to " << x << " took " <<
        round(static_cast<std::chrono::duration<double>>((std::chrono::high_resolution_clock::now() - starttime)).count())
        << " seconds.";
}

【问题讨论】:

  • 我猜标题与问题正文相反。
  • 哎呀抱歉,正在修复它
  • 我敢打赌(我目前无法检查)是使用向量在内存访问上花费的时间比在整数模上保存的时间要多。请注意,您只需要检查除数直到 i 的平方根,包括在内。这样可以节省很多时间。
  • 性能时序技术调查:stackoverflow.com/a/5694432/576911
  • 确保您测试优化版本,调试版本。

标签: c++ loops vector primes


【解决方案1】:

因为第三种方法使用vector&lt;unsinged int&gt;。 特别是 primes.push_back 会导致分配。最初尝试primes.reserve

【讨论】:

  • 多少钱?我可以根据 x 使其动态化吗?
  • 如果您不关心内存使用情况,primes.reserve(x) 当然就足够了。否则对于大数,我会找到一些素数的统计数据
  • 我做了 primes.reserve(x / log10(x / 1.08366));
  • 预留槽也需要 30 秒
【解决方案2】:

我想说的主要问题是,最常见的数字可以被 2 整除,因此它不是素数。我想第一种方法对编译器和缓存更友好。但很难确定。此外,尝试删除打印并测试所花费的时间。根据使用情况,打印往往会大大降低代码速度。

一种确定所有素数的标准方法(有更有效的方法,但这个方法相当简单)。

  1. 创建布尔向量A,用于指示数字是否为素数。但在开始时将所有变量设置为 true - 除了A[0]=A[1]=false

  2. i = 2 to x 运行 for 循环。如果 A[i] 为假,则跳过它 - i 不是素数。如果A[i] 为真,则i 为素数,并将所有A[i*k] 设置为假1&lt;k&lt;x/i

这两种方法都应该更有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 2019-05-29
    • 2021-04-28
    • 2016-07-01
    • 2011-05-28
    • 2012-10-24
    相关资源
    最近更新 更多