找到 40 亿以下所有素数的最快方法
Fastest way to find all primes under 4 billion
我正在尝试打印 2**32 以下的每个质数。 现在我正在使用布尔向量来构建筛子,然后在制作筛子后打印出素数。 打印出高达 10 亿的素数需要 4 分钟。 有没有更快的方法来做到这一点??这是我的代码
#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;
我在我的博客上讨论了生成大量素数的问题,我发现前十亿素数的总和是11138479445180240497。我描述了四种不同的方法:
-
蛮力,使用试验除法测试从 2 开始的每个数字。
-
使用 2,3,5,7 轮生成候选者,然后用强伪素数检验以 2、7 和 61 为底测试素数; 这种方法最多只能有效 2^32,这不足以让我对前十亿个素数求和,但对你来说已经足够了。
-
由于Melissa O'Neill使用嵌入在优先级队列中的筛子的算法,这非常慢。
-
埃拉托色尼的分段筛,速度非常快,但需要空间来存储筛子和筛子本身。
这可能会加快速度:
#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;
}
它有点像埃拉托色尼筛子的倒数(不是从限制下的每个数字开始并消除倍数,而是从 2 开始并忽略倍数直到极限)。
最快的方法可能是获取预生成的列表。
http://www.bigprimes.net/有前 14 亿个素数可供下载,其中应包括 300 亿以下的每个素数。
我想加载二进制文件在几千兆字节时可能需要很长时间。
您是否对花费最多时间的内容进行了基准测试?是筛子本身,还是输出的写入?
加快筛子速度的一种快速方法是停止担心所有偶数。只有一个偶数是素数,您可以对其进行硬编码。这将数组的大小减少一半,如果您遇到物理内存的限制,这将非常有帮助。
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
输出它可能更有效。您甚至可以走老派,将fwrite
与stdout
一起使用。
我在 Ryzen 9 3900x 上使用单个线程在 C 语言中编写了一种快速方法,可以在三分钟内输出多达 40 亿的素数。如果将其输出到文件,它最终是 2.298GB,我认为它使用大约 20GB 的内存来完成。
#include <stdlib.h>
#include <stdio.h>
#define ARRSIZE 4000000000
#define MAXCALC ARRSIZE/2
int main() {
long int z;
long int *arr = (long int*) malloc((ARRSIZE) * sizeof(long int));
for (long int x=3;x <= MAXCALC; x++) {
if (x % 10 == 3 || x % 10 == 7 || x % 10 == 9) {
for (long int y=3; y < MAXCALC; y++){
z = x * y;
if (z < ARRSIZE)
arr[z] = 1;
else
break;
}
}
}
printf("2 3 5 ");
for (long int x=7; x < ARRSIZE; x++) {
if (x % 2 != 0 && x % 10 != 5)
if (arr[x] != 1)
printf("%ld ", x);
}
printf("n");
free(arr);
return EXIT_SUCCESS;
}
我编写了代码 i python,在 8.7 秒内输出所有小于十亿的素数。但我不确定你是前40亿个素数还是艾伦素数比这少。无论如何,这是我的解决方案:
import numpy as np
from math import isqrt
def all_primes_less_than(n):
is_prime = np.full(n,True)
is_prime[:2] = False
is_prime[4::2] = False
for p in range(3,isqrt(n),2):
if is_prime[p]: is_prime[p*p::p] = False
return is_prime.nonzero()[0]
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- std::find,返回所有找到的值的替代方法,而不仅仅是存在重复的向量的第一个值
- 找到一种有效的方法,在 2 个巨大的缓冲区上执行 MAX,每字节字节
- 硬币兑换:找到多种方法来重现给定的总和
- 是否有通用方法可以找到任何以 null 结尾的字符串的长度?
- 有没有一种惯用的方法可以在不存储变换或不必要地重新计算的情况下找到数组变换的最小/最大值?
- 在使用库时,找到要链接的必要库的快速方法是什么
- 有没有一种 STL 方法可以找到字符串的所有排列,给出一个以 C++ 为单位的大小?
- 找到一种使用 C++ 中的条件提取浮点数的方法
- 当使用Lua作为嵌入式语言(比如c++)时,有什么简单/方便的方法可以找到变量在Lua中的定义位置吗
- Sizeof返回的是指针大小,而不是数组大小.有其他方法可以找到尺寸吗
- 找到所有与自己求和的数字X的快速方法,去掉一个数字得到N
- 找到不大于 A 的最大数的最有效方法,该数可被 B 整除
- 找到稀疏矩阵(特征)最大值的有效方法
- 找到分区数组的方法数量
- 在std :: Map或std :: set中找到具有给定前缀的键的优雅方法
- 从另一个向量中搜索和找到元素的有效方法
- 在向量中找到连续数字的更有效方法
- 牛顿方法找到立方根,答案每次都显示为0
- 是否有一个很好的方法找到两个变量的模数使用SSE?(没有SVML)