如何为一个非常大的筛子保留记忆?

时间:2013-03-25 15:48:15

标签: c++ arrays memory-management limit

我希望通过筛选高达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;
    }
}

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:3)

数组素数的大小为100 MB,并且不允许在堆栈上声明如此大的数组。尝试将数组放在全局范围内以将其分配到堆上,或者使用new(in C++)或malloc(in C)分配它。在那之后不要忘记释放记忆!

答案 1 :(得分:2)

变量可以存储在三个不同的存储区中:静态存储器,自动存储器,动态存储器。自动内存(非静态局部变量)的大小有限,你越过它,这会使程序崩溃。另一种方法是将数组标记为静态,这将把数组放在静态存储中,或使用动态内存。

因为这是标记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类似,但大小不变,你必须将其标记为静态以避免在自动内存中占用空间。

你没有问过,但Erastostenes Sieve并不是计算大量素数的最快算法。似乎Sieve of Atkin更快并且使用更少的内存。

1 - 当你的系统有8位字节时。

答案 2 :(得分:1)

你应该制作一个这样大小的整体筛子。相反,使用分段的Eratosthenes筛子在连续的段中进行筛分。在第一段,计算该段内每个筛分素数的最小倍数,然后以正常方式将筛选质数的倍数标记为复合;当所有筛选质数都被使用时,该段中剩余的未标记数字是素数。然后,对于下一个段,每个筛分素数的最小倍数是结束前一个段中筛分的倍数,因此筛分一直持续到完成。

考虑从20到200的段中筛选100到200的例子; 5个筛分质数分别为3,5,7,11和13.在100到120的第一个段中,比特阵有10个槽,槽0对应101,槽 k 对应100 + 2 * k * + 1,插槽9对应119.段中3的最小倍数为105,对应插槽2;时隙2 + 3 = 5和5 + 3 = 8也是3的倍数.5的最小倍数在时隙2是105,而时隙2 + 5 = 7也是5的倍数.7的最小倍数是105在插槽2处,插槽2 + 7 = 9也是7的倍数。依此类推。

函数primes接受参数 lo hi delta ; lo hi 必须是偶数, lo &lt; hi lo 必须大于 hi 的平方根。段大小是 delta 的两倍。长度为 m 的数组 ps 包含的筛选素数小于 hi 的平方根,其中2被删除,因为偶数被忽略,由正常的Eratosthenes筛。数组 qs 包含相应筛分素数的当前片段中最小倍数的筛子比特阵列的偏移量。在每个段之后, lo 前进两次 delta ,因此对应于 sieve的索引 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 的价值至关重要;为了速度,你应该使 delta 尽可能大,以便它适合高速缓冲存储器。使用您的语言库来进行比特阵列,这样您只需为每个筛选位置取一个位。如果您需要一个简单的Eratosthenes筛子来计算筛分质数,这是我最喜欢的:

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

您可以在my blog看到更多涉及素数的算法。