C - 分段筛失去素数

时间:2017-04-27 19:22:45

标签: c sieve-of-eratosthenes

#include <stdio.h>
#include <math.h>

void sieve(unsigned int up, unsigned int low, unsigned char primes[]);

main()
{
    unsigned int low, up;
    unsigned int steps;
    scanf("%d",&steps);
    for (unsigned int i=0;i<steps;i++){
        scanf("%d %d",&low,&up);

        unsigned char v[up-low];
        sieve (up, low, v);
        for(unsigned int j=0; j<up-low+1; j++){
            if (v[j] == 1){
                printf("%d\n",low+j);
            }
        }   
    }
}
//-------------------------------------------------------------------
void sieve(unsigned int up, unsigned int low, unsigned char primes[])
{
    for (unsigned int i=0;i<up-low+1;i++){
        primes[i]=1;
    }

    for (unsigned int i=2;i<sqrt(up+1);i++) {
        for (int j=((low/i)*i)+i;j<up+1;j+=i){
                primes[j-low] = 0;


        }
    }
}

我正在尝试查找特定范围内的素数。我正在使用Erastothenes的分段筛,但不幸的是它丢失了一些素数,这是因为:

for (int j=((low/i)*i)+i;j<up+1;j+=i){
                    primes[j-low] = 0;

i大于我的下限筛子功能时,开始用0值标记素数,毕竟它们不在我的标准输出中。

  

例如stdin:
  1
  2 1000
  例如stdout:
  2
  37它丢失了2到37之间的所有素数   41个
  43个
  ......

通过算法总是将下限值识别为素数。

  

例如stdin:
  4 10

     

例如stdout:
  4
  5
  7

我需要一些帮助来调整我的算法以正确标记这些数字,因为在几个小时之后我真的无能为什么条件让它起作用。

2 个答案:

答案 0 :(得分:1)

首先,您有一个错误的错误。你的数组不够大,无法容纳所有元素的标志。把它做得更大:

unsigned char v[up-low+1];

现在主要问题出在你的循环中:

for (unsigned int i=2;i<sqrt(up+1);i++) {
    for (int j=((low/i)*i)+i;j<up+1;j+=i){
        primes[j-low] = 0;
    }
}

您没有从正确的索引开始。在low==4的情况下,内循环的第一次迭代将j设置为((4/2)*2)+2 == (2*2)+2 == 4*2 == 6,因此您将完全跳过4。

保持简单。在j处开始i*2。在循环中,跳过j小于low的任何值:

for (unsigned int i=2;i<sqrt(up+1);i++) {
    for (unsigned int j=i*2;j<up+1;j+=i){
        if (j < low) continue;
        primes[j-low] = 0;
    }
}

答案 1 :(得分:0)

您可以尝试分析我的c ++解决方案以获得分段筛选,因为网上没有很多分段筛分正确的实现。我希望它可以帮助你理解它是如何工作的。干杯!

void sito_delta( int delta, std::vector<int> &res)
{

std::unique_ptr<int[]> results(new int[delta+1]);
for(int i = 0; i <= delta; ++i)
    results[i] = 1;

int pierw = sqrt(delta);
for (int j = 2; j <= pierw; ++j)
{
    if(results[j])
    {
        for (int k = 2*j; k <= delta; k+=j)
        {
            results[k]=0;
        }
    }
}

for (int m = 2; m <= delta; ++m)
    if (results[m])
    {
        res.push_back(m);
        std::cout<<","<<m;
    }
};
void sito_segment(int n,std::vector<int> &fiPri)
{
int delta = sqrt(n);

if (delta>10)
{
    sito_segment(delta,fiPri);
   // COmpute using fiPri as primes
   // n=n,prime = fiPri;
      std::vector<int> prime=fiPri;
      int offset = delta;
      int low = offset;
      int high = offset * 2;
      while (low < n)
      {
          if (high >=n ) high = n;
          int mark[offset+1];
          for (int s=0;s<=offset;++s)
              mark[s]=1;

          for(int j = 0; j< prime.size(); ++j)
          {
            int lowMinimum = (low/prime[j]) * prime[j];
            if(lowMinimum < low)
                lowMinimum += prime[j];

            for(int k = lowMinimum; k<=high;k+=prime[j])
                mark[k-low]=0;
          }

          for(int i = low; i <= high; i++)
              if(mark[i-low])
              {
                fiPri.push_back(i);
                std::cout<<","<<i;
              }
          low=low+offset;
          high=high+offset;
      }
}
else
{

std::vector<int> prime;
sito_delta(delta, prime);
//
fiPri = prime;
//
int offset = delta;
int low = offset;
int high = offset * 2;
// Process segments one by one 
while (low < n)
{
    if (high >= n) high = n;
    int  mark[offset+1];
    for (int s = 0; s <= offset; ++s)
        mark[s] = 1;

    for (int j = 0; j < prime.size(); ++j)
    {
        // find the minimum number in [low..high] that is
        // multiple of prime[i] (divisible by prime[j])
        int lowMinimum = (low/prime[j]) * prime[j];
        if(lowMinimum < low)
            lowMinimum += prime[j];

        //Mark multiples of prime[i] in [low..high]
        for (int k = lowMinimum; k <= high; k+=prime[j])
            mark[k-low] = 0;
    }

    for (int i = low; i <= high; i++)
        if(mark[i-low])
        {
            fiPri.push_back(i);
            std::cout<<","<<i;
        }
    low = low + offset;
    high = high + offset;
}
}
};

int main()
{
std::vector<int> fiPri;
sito_segment(1013,fiPri);
}