如何为一个非常大的筛保留内存?

How can I reserve memory for a very large sieve?

本文关键字:非常 保留内存 一个      更新时间:2023-10-16

我想通过筛选最多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接受参数lohidelta;lohi必须是偶数,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

你可以在我的博客上看到更多关于质数的算法