简体   繁体   English

C ++质数间隔

[英]C++ prime numbers interval

I have to write script to print prime numbers in given range. 我必须编写脚本以在给定范围内打印素数。 Currently I am using the following script: 目前,我正在使用以下脚本:

#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;
}

It works fine for small inputs (it prints 1 as prime but that is easy to fix). 它适用于小输入(它打印1作为质数,但很容易解决)。 However, when I input numbers like 1999998973 and 1999999973 it crashes with bad_alloc . 但是,当我输入数字1999998973和1999999973时,它会与bad_alloc崩溃。

I know I probably made a huge array, but I don't know how to fix it. 我知道我可能做了很多工作,但我不知道如何解决。 I have tried a different algorithm but it was really slow, I need it to print the numbers within about 2 seconds or so. 我尝试了一种不同的算法,但是它确实很慢,我需要它在大约2秒钟左右的时间内打印数字。 Does anyone have an idea? 有人有主意吗?

This seems to work for the numbers I looked at from 2 to 500. It doesn't blow up with the 1999998973 to 1999999973 range and gives these results which I don't know if they are correct or not: 这似乎适用于我从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 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 1999999 1999199919999991999 19999991999 19999991999 19999991999

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;

The problem is the space of your array. 问题是阵列的空间。

Option 1: you can reduce the array to the size of the range. 选项1:您可以将数组缩小为范围的大小。 You gain space, but you have extra calculation, because you have to consider all numbers outside the range in your eratostene sieve. 您可以获得空间,但是您需要进行额外的计算,因为您必须考虑所有在eratostene筛子范围内的数字。

Option 2: copress your data using a bit instead of an int. 选项2:使用位而不是整数共压缩数据。 You can do this easily with vector<bool> which is designed to exactly that. 您可以使用vector<bool>轻松地做到这一点, vector<bool>正是为此而设计的。

With option 2 you can keep your code as it is, just changing arr to: 使用选项2,您可以保持代码不变,只需将arr更改为:

vector<bool> arr(m+1);

You could even save yourself the initialisation loop with: 您甚至可以使用以下命令保存初始化循环:

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

Whatever option you take, I'd suggest to replace the inner loop of your eratostene sieve with an additive version: 无论您采取哪种选择,我都建议用添加的版本替换您的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;
        }
    }
}

Time 时间

Save space increases time. 节省空间会增加时间。 However I doubt that even if you had enough memory that you'd get an answer within 2 secs for your so huge numbers. 但是我怀疑,即使您有足够的内存,您也无法在2秒内得到如此庞大的数字的答案。 If you have to process 2 000 000 000 numbers it would require that each number is processed in maximum 1 nanosecond, ie one single CPU instruction to meet your expectations. 如果必须处理2 000 000 000个数字,则要求每个数字最多处理1纳秒,即一条CPU指令即可满足您的期望。

I suggest changing the algorithm using wheel factorization . 我建议使用轮子分解来更改算法。

As described in the first paragraph of the provided link, you can determine if a number is a prime by dividing 2,3,5 and then divide by numbers congruent to modulo 30 until the square root of the number . 如所提供的链接的第一段所述,您可以通过除以2,3,5,然后除以等于30的模数直到数字的平方根,来确定数字是否为质

One such implementation is listed below. 下面列出了一种这样的实现。 By checking for primes this way, you won't need to create arrays up to m . 通过以这种方式检查素数,您将不需要创建最大为m数组。 The only array you'll need is wheelOf30[] . 您唯一需要的数组是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;
}

Your main program would look like this: 您的主程序如下所示:

#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM