在某个范围内查找素数时出现 Sigsegv 错误

Sigsegv Error in finding prime in a range

本文关键字:Sigsegv 错误 范围内 查找      更新时间:2023-10-16

在解决问题以找到给定范围内的素数时,我收到Sigsegv错误,我无法找到我的错误在哪里以及如何纠正它

#include<iostream>
#include<cmath>
using namespace std;
int primes[10000000];// stores prime upto a max value
int prime[10000000];//stores prime in a given range
int main()
{
  long long int t,m,n,s,k,q;
  for(long long int i=1;i<=1000000;i++){
      primes[i]=1;
      primes[1]=0;
  }
    //stores prime using sieve    
    for(long long int i=2;i<=sqrt(1000000);i++) 
    {
        if(primes[i]==1)
        {
            for(long long int j=2;i*j<=1000000;j++)
            {
                primes[i*j]=0;
            }
        }   
    }
    cin>>t;
    while(t--)
    {
        cin>>m>>n;
        //marking all indices as 1 
        for(long long int i=m;i<=n;i++)      
        {
          prime[i]=1;
        }
        //calculating which offset to mark
        for(long long int i=2;i<=n-m+1;i++)       
        {
            if(primes[i]==1)
            {
                long long int x=(m/i)*i;
                while(x<m)
                x=x+i;   
                for(long long int j=x;j<=n;j=j+i)
                {
                    if(primes[j]==0)
                    prime[j]=0;
               }  
             }
           }         
        for(long long int i=m;i<=n;i++)
        {
            if(prime[i]==1&&i!=1)
            cout<<i<<"n";
        }
    }
    return 0;
}

您使用的编译器可能不允许静态分配大块数据,例如

int primes[10000000];

这超过 2^25 个字节。如此大的块可能会超出编译器或其在 SPOJ 上的运行时的能力。也许可以newmalloc()这么大的块,但这种解决方法可能会把你引向死胡同。

另一个问题是,您正在从输入中读取mn,而没有验证它们是否在安全范围内。SPOJ 上的至少一个测试用例将比代码限制高出两个数量级,因为您的分配是 10^7,但 SPOJ 限制是 10^9。这意味着崩溃是不可避免的。

你不需要一个完整的32位整数来保存布尔值;你可以使用bool,从而将内存需求减少到四分之一。或者,您可以将每个字节大小的数组单元视为包含 8 位的打包位图,从而将内存使用量减少到 1/32。而且由于您使用的是C++,因此所有东西都已经以std::vector<bool>的形式为您整齐地打包了(在引擎盖下进行位打包)。

注意:数组必须大一百倍才能筛分所有数字,直到 PRIME1 限制 1,000,000,000。尽管可以筛选该范围内的所有数字(时间限制非常慷慨 - 大约是此任务所需值的 10000 倍),但对于完全不熟悉编程的人来说,这可能并不容易。

但是,该任务并不要求筛选十亿个数字。它只要求筛选一小部分范围,每个范围不超过100001个数字。即使是简单的、未经优化的代码也可以在一毫秒内完成这项工作,即使std::vector<bool>比任何合理的数据结构慢一个数量级。

要注意的关键词是"埃拉托色尼的窗筛"。在代码审查中,有数百个主题涉及 PRIME1。看一眼。

考虑一个案例:

1
100000000 100000009

当我在 ideone 链接上运行您的代码时:这里。

它给出了运行时错误。


原因:您已初始化大小为 10 7 的素数组,但m, n的范围最多可以达到 109

因此,一旦遇到prime[i]=1,您的系统就会崩溃。

for(long long int i=m;i<=n;i++)      
{
      prime[i]=1;
}

建议:学习埃拉托色尼的筛子。而且由于m, n的范围可以是
1 <= m <= n <= 1000000000, n-m<=100000

如果我们取 109 的 sqrt 根,那么它将接近 31622。所以,这就是为什么我们拿起了一个大小为 32000 的数组num(在我的代码中)。之后,我们计算了位于 2 - 32000 范围内的素数数量。

现在,考虑三种情况:

  1. m and n两者都小于 32000 时。然后只需使用计算出的prime数组并打印所需的质数。

  2. 当两个m and n都在 32000 的范围之外时,请检查i(在 m 和 n 范围内)是否不能被任何素数(存在于代码prime数组中)整除。如果i不能被任何数字整除,则打印它。

  3. 如果m and n的范围部分小于 32000,部分超出 32000。然后将范围分成两部分,一部分完全小于并等于 32000,另一部分完全大于 32000。并对第一个范围重复步骤-1,对第二个范围重复步骤-2。

下面是我的代码,请发现它很有用,但不要将其复制并粘贴到 SPOJ 上。

#include<stdio.h>
#include<math.h>
int num[32000] = {0},prime[3500],prime_index = -1;
int main() {
    prime[++prime_index] = 2;
    int i,j,k;
    for(i=3;    i<179;     i += 2) {
        if(num[i] == 0) {
            prime[++prime_index] = i;
            for(j = i*i, k = 2*i;    j<=32000;   j += k) {
                num[j] = 1;
            }
        }
    }
    for(;   i<=32000;   i+= 2) {
        if(num[i] == 0) {
            prime[++prime_index] = i;
        }
    }
    int t,m,n;
    scanf("%i",&t);
    while(t--) {
        scanf("%i%i",&m,&n);
        if(m == 1)
            m++;
        if(m == 2 && m <= n) {
            printf("2n");
        }
        int sqt = sqrt(n) + 1, arr[100005] = {0};
        for(i=0;    i<=prime_index; i++) {
            if(prime[i] > sqt) {
                sqt = i;
                break;
            }
        }
        for(;   m<=n && m <= prime[prime_index];   m++) {
            if(m&1 && num[m] == 0) {
                printf("%in",m);
            }
        }
        for(i=0;    i<=sqt;     i++) {
            j = prime[i] * (m / prime[i]);
            if(j < m) {
                j += prime[i];
            }
            for(k=j;    k<=n;   k += prime[i]) {
                arr[k-m] = 1;
            }
        }
        for(i=0;    i<=n-m; i++) {
            if(!arr[i]) {
                printf("%in",m+i);
            }
        }
        printf("n");
    }
    return 0;
}

欢迎任何疑问评论。