如何为一个非常大的筛保留内存?
How can I reserve memory for a very large sieve?
我想通过筛选最多100,000,000来生成素数,但是声明这个范围的bool数组会使程序崩溃。这是我的代码:
long long i,j,n;
bool prime[100000000+1];
prime[1]=prime[0]=false;
for(i=2;i<=100000000;i++){
prime[i]=true;
}
for(i=2;i<=100000000;i++){
if(prime[i]==false){
continue;
}
for(j=i*2;j<=100000000;j+=i){
prime[j]=false;
}
}
我该如何解决这个问题?
数组素数的大小为100 MB,不允许在堆栈上声明这么大的数组。尝试将数组放置在全局作用域中以在堆上分配它,或者使用new(在C++
中)或malloc(在C
中)分配它。之后别忘了释放内存!
变量可以存储在三个不同的内存区域:静态内存,自动内存,动态内存。自动内存(非静态局部变量)的大小是有限的,如果您越过了它,就会导致程序崩溃。另一种方法是将数组标记为静态,这将把数组放在静态存储中,或者使用动态内存。
因为它被标记为c++…使用std::vector
,简单易用,使用动态内存。
#include <vector>
//...
//...
long long i,j,n;
std::vector<bool> prime(100000000+1, true);
prime[1]=prime[0]=false;
for(i=2;i<=100000000;i++){
if(prime[i]==false){
continue;
}
for(j=i*2;j<=100000000;j+=i){
prime[j]=false;
}
}
std::vector<bool>
使用"位效率"表示,这意味着std::vector在这里将占用比传统数组少8 1倍的内存。
std::bitset
与此类似,但其大小是恒定的,您必须将其标记为静态,以避免占用自动内存中的空间。
你没有问过,但erastones Sieve并不是计算大量素数的最快算法。似乎筛子的Atkin更快,使用更少的内存。
1 -当你的系统有8位字节时
您不应该制作一个如此大小的单片筛。相反,使用埃拉托色尼分段筛在连续段进行筛分。在第一段,计算该段内各过筛素数的最小倍数,然后按常规将各过筛素数的倍数标记为复合;当所有的过筛质数用完后,段中剩余的未标记数为质数。然后,对于下一段,每个过筛素数的最小倍数是在前一段中结束过筛的倍数,因此继续过筛直到完成。
考虑从100到200分20段筛分的例子;5个过筛质数分别是3、5、7、11和13。在100 ~ 120的第一段中,bitarray有10个槽位,槽位0对应101,槽位k对应100 + 2*k* + 1,槽位9对应119。段中3的最小倍数为105,对应槽2;槽2+3=5和5+3=8也是3的倍数。槽2上5的最小倍数是105,槽2+5=7也是5的倍数。槽2上7的最小倍数是105,槽2+7=9也是7的倍数。等等。
函数primes
接受参数lo, hi和delta;lo和hi必须是偶数,lo <<em>hi和lo必须大于hi的平方根。段大小为的两倍δ 。长度m的数组ps包含小于hi的平方根的筛质数,因为忽略偶数而去掉2,使用埃拉托色尼的普通筛法计算。数组qs包含在筛子位数组中对应筛子素数当前段中最小倍数的偏移量。在每个片段之后,lo向前移动两次delta,因此筛子位数组的索引i对应的数字是lo + 2 i + 1。
function primes(lo, hi, delta)
sieve := makeArray(0..delta-1)
ps := tail(primes(sqrt(hi)))
m := length(ps)
qs := makeArray(0..m-1)
for i from 0 to m-1
qs[i] := (-1/2 * (lo + ps[i] + 1)) % ps[i]
while lo < hi
for i from 0 to delta-1
sieve[i] := True
for i from 0 to m-1
for j from qs[i] to delta step ps[i]
sieve[j] := False
qs[i] := (qs[i] - delta) % ps[i]
for i from 0 to delta-1
t := lo + 2*i + 1
if sieve[i] and t < hi
output t
lo := lo + 2*delta
对于上面给出的示例,这称为primes(100, 200, 10)
。在上面的例子中,qs
初始值为[2,2,2,10,8],对应最小倍数105,105,105,121和117,第二段复位为[1,2,6,0,11],对应最小倍数123,125,133,121和143。
δ 的值至关重要;为了提高速度,您应该使delta尽可能大,以便它适合缓存内存。对bitarray使用您的语言库,这样每个筛选位置只取一个位。如果你需要一个简单的埃拉托色尼筛法来计算筛质数,这是我最喜欢的:
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve(p)
output p
for i from p * p to n step p
sieve[i] := False
你可以在我的博客上看到更多关于质数的算法
- 必须为 C++20 协程帧保留多少内存?
- 将 mmap 内存用于开销非常低的循环缓冲区
- 内存映射文件访问非常慢
- 为异步发送缓冲区保留内存(提升 asio 套接字)
- std::vector<std::vector<int>>:调试断言失败。C++矢量下标超出范围保留内存
- 如何在Windows和更高版本上保留内存,并将文件映射到内存中
- 结构中的C++数组指针保留内存位置,但丢失所有值
- 是否更正PInvoke签名以使用带有C#保留内存的嵌套结构
- C++ - 关闭应用程序后保留内存
- 如何在 Windows 映射程序的 DLL 之前保留内存区域?
- 需要释放具有保留内存的 c++ Do 局部变量
- (C++)循环:不保留内存的用户输入
- OpenCL:减少示例,并保留内存对象/将cuda代码转换为OpenCL
- 如何为向量的向量保留内存
- 为结构体保留内存空间时
- 如何在构造时为std::vector保留内存?
- 如何为一个非常大的筛保留内存?
- 在堆中保留内存错误
- 为什么std::deque不是一个在索引0之前保留内存的向量
- 如何判断已提交内存和保留内存中的内容