C ++素数区间

时间:2014-10-18 12:12:22

标签: c++ arrays intervals sieve-of-eratosthenes

我必须编写脚本来打印给定范围内的素数。目前我正在使用以下脚本:

#include <iostream>
using namespace std;
int main()
{
    int n,p,m;
    cin>>n >> m;
    int * arr;

    arr= new  int[m+1];

    for (int i=0; i<=m; i++)
    {
      arr[i]=0;
    }

    for(int i=2;i<=m;i++){
        if(arr[i]==0)
        {   p=i;
            for (int j=2;p*j<=m;j++)
            {
                arr[p*j]=1;
            }
        }
    }

    for(int i=n;i<=m;i++){
        if(arr[i]==0)cout<<i<<endl;
    }
    delete[] arr;
    return 0;
}

它适用于小输入(它打印1作为素数,但很容易修复)。但是,当我输入像1999998973和1999999973这样的数字时,它会与bad_alloc一起崩溃。

我知道我可能制作了一个巨大的阵列,但我不知道如何修复它。我尝试了不同的算法,但它确实很慢,我需要它在大约2秒左右的时间内打印数字。有没有人有想法?

3 个答案:

答案 0 :(得分:0)

这似乎适用于我从2到500看的数字。它不会爆炸 1999998973至1999999973范围并给出这些结果,我不知道它们是否正确:

1999999003 1999999013 1999999049 1999999061 1999999081 1999999087 1999999093 1999999097 1999999117 1999999121 1999999151 1999999171 1999999207 1999999219 1999999271 1999999321 1999999373 1999999423 1999999439 1999999499 1999999553 1999999559 1999999571 1999999609 1999999613 1999999621 1999999643 1999999649 1999999657 1999999747 1999999763 1999999777 1999999811 1999999817 1999999829 1999999853 1999999861 1999999871 1999999873 1999999913 1999999927 1999999943 1999999973

int n,p,m;
cout << "enter two numbers" << endl;
cin >> n >> m;
int size = (m - n) + 1; 

int * arr = new  int[size];

// initialize the array to all zeros
for (int i=0; i < size; i++)
{
  arr[i]=0;
}
// loop once for the entire set of numbers from 2 to max value to 
// multiply with (sqrt of top of range)
int max = sqrt(m);

for(int i = 2; i <= max ;i++)
{
    p = i;
    for (int j=2 ; p*j <= m ; j++)
    {
        if ( (p * j) >= n  )
        {
           arr[(p*j) - n] = 1;
        }
    }
}

for(int i = 0; i < size; i++)
{
    if ( arr[i]==0 )
        cout << (i + n) << endl;
}
delete[] arr;

答案 1 :(得分:0)

问题是阵列的空间。

选项1:您可以将数组缩小到范围的大小。你获得了空间,但你有额外的计算,因为你必须考虑你的eratostene筛子范围之外的所有数字。

选项2:使用bit而不是int来压缩数据。您可以使用专为此设计的vector<bool>轻松完成此操作。

使用选项2,您可以保持代码不变,只需将arr更改为:

vector<bool> arr(m+1);

你甚至可以用以下方法保存自己的初始化循环:

vector<bool>arr(m+1, false);

无论你采取什么选择,我都建议用添加剂替换你的eratostene筛的内环:

for (int i = 2; i <= m; i++){    
    if (arr[i] == 0)
    {
        for (int j = i*2; j <= m; j+=i)  // no p, no multiplication, just add i at each iteration
        {
            arr[j] = 1;
        }
    }
}

时间

节省空间增加时间。但是我怀疑,即使你有足够的记忆力,你也可以在2秒内得到答案。如果必须处理2 000 000个数字,则需要处理每个数字最多1纳秒,即一条CPU指令以满足您的期望。

答案 2 :(得分:0)

我建议使用wheel factorization更改算法。

如所提供链接的第一段所述,您可以通过除以2,3,5来确定数字是否为素数,然后将数字除以等于30的数字直到square root of the number

下面列出了一种这样的实现方式。 通过这种方式检查质数,您不需要创建最多m的数组。 您唯一需要的数组是wheelOf30[]

#include <math.h>

static const bool wheelOf30[] = {
    false,  true, false, false, false, false, false,  true, false, false,  //  1,  7,
    false,  true, false,  true, false, false, false,  true, false,  true,  // 11, 13, 17, 19,
    false, false, false,  true, false, false, false, false, false,  true   // 23, 29.
};

bool isPrime(int num)
{
    // first, modulo by 2, 3, and 5
    if ((num % 2 == 0) || (num % 3 == 0) || (num % 5 == 0))
        return false;

    int rootNum = sqrt(num);
    // and then, divide by the congruent numbers represented by wheel of 30
    for (int i = 7; i <= rootNum; i += 2)
    {
        // divide the number with the ones congruency to modulo 30 is true
        if (wheelOf30[ i % 30 ])
        {
            if (num % i == 0)
                return false;
        }
    }

    return true;
}

您的主程序将如下所示:

#include <iostream>

extern bool isPrime(int num);

int main(int argc, const char * argv[])
{
    int n, m;
    cin >> n >> m;

    for (int i=n; i<=m; ++i)
        if (isPrime(i))
            cout << i << endl;
}