找到40亿以下所有素数的最快方法

时间:2013-09-21 01:49:04

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

我正在尝试打印2 ** 32下的每个素数。现在我正在使用bool载体构建筛子,然后在筛子后打印出素数。只需4分钟即可打印出高达10亿的素数。有更快的方法吗?这是我的代码

#include <iostream>
#include <cstdlib>
#include <vector>
#include <math.h>

using namespace std;

int main(int argc, char **argv){
  long long limit = atoll(argv[1]);
  //cin >> limit;
  long long sqrtlimit = sqrt(limit);

  vector<bool> sieve(limit+1, false);

  for(long long n = 4; n <= limit; n += 2)
    sieve[n] = true;

  for(long long n=3; n <= sqrtlimit; n = n+2){
    if(!sieve[n]){
      for(long long m = n*n; m<=limit; m=m+(2*n))
        sieve[m] = true;
    }
  }

  long long last;
  for(long long i=limit; i >= 0; i--){
    if(sieve[i] == false){
      last = i;
      break;
    }
  }
  cout << last << endl;

  for(long long i=2;i<=limit;i++)
  {
    if(!sieve[i])
      if(i != last)
        cout<<i<<",";
      else
        cout<<i;
  }
  cout<<endl;

4 个答案:

答案 0 :(得分:4)

我讨论了在blog生成大量素数的问题,在那里我发现第一个十亿素数的总和是11138479445180240497.我描述了四种不同的方法:

  1. 蛮力,使用试验分部从2开始测试每个数字。

  2. 使用2,3,5,7轮生成候选者,然后用强伪测试测试素数到基础2,7和61;这个方法最多只能达到2 ^ 32,这对我来说不足以对第一个十亿个素数求和,但对你来说已足够了。

  3. Melissa O'Neill的一种算法,它使用嵌入优先级队列的筛子,速度非常慢。

  4. Eratosthenes的分段筛,速度非常快,但需要空间来储存筛分素和筛子本身。

答案 1 :(得分:0)

这可能会加快一点:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<unsigned long long> numbers;
    unsigned long long maximum = 4294967296;
    for (unsigned long long i = 2; i <= maximum; ++i)
    {
        if (numbers.empty())
        {
            numbers.push_back(i);
            continue;
        }

        if (std::none_of(numbers.begin(), numbers.end(), [&](unsigned long long p)
        {
            return i % p == 0;
        }))
        {
            numbers.push_back(i);
        }

    }

    std::cout << "Primes:  " << std::endl;
    std::copy(numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout, " "));

    return 0;
}

它与Eratosthenes的筛子相反(不是从限制下的每个数字开始并消除倍数,而是从2开始并忽略倍数到极限)。

答案 2 :(得分:0)

最快的方法可能是采用预生成列表。

http://www.bigprimes.net/有可供下载的前14亿个素数,其中应包括每个低于300亿左右的素数。

我认为加载二进制文件可能需要很长时间才能达到几千兆字节。

答案 3 :(得分:0)

您是否对最耗费时间的人进行了基准测试?它是筛子本身,还是输出的写作?

加速筛子的一个快速方法是停止担心所有偶数。只有一个偶数是一个素数,你可以硬编码。这会将你阵列的大小减少一半,如果你遇到物理内存的极限,这将有很大的帮助。

vector<bool> sieve((limit+1)/2, false);
...
  for(long long m = n*n/2; m<=limit/2; m=m+n)
    sieve[m] = true;

至于输出本身,cout是非常低效的。自己调用itoa或某些等效项可能更有效,然后使用cout.write输出它。您甚至可以上学,并将fwritestdout一起使用。