2012-02-20 4 views
3

私はEratosthenesのセグメント化された篩を使用して問題PRIME1を解決しようとしています。私のプログラムは普通のふるいで正しく動作します。これは最大でNEW_MAXです。しかし、セグメント化されたふるい分けが行われるケースn > NEW_MAXに問題があります。そのような場合は、単にすべての数字を出力します。あなたの応答ダニエルFRありがとう:http://ideone.com/8H5lK#view_edit_boxエラトステネのふるいを使ってPRIME1を使用する(C)

/* segmented sieve */ 
#include <math.h> 
#include <stdio.h> 
#include <stdlib.h> 
#define MAX_LIMIT 1000000000 //10^9 
#define NEW_MAX 31623 /*SQUARE ROOT OF 1000000000*/ 
#define MAX_WIDTH 100000 //10^5 
char flags[NEW_MAX+100]; /*TO PREVENT SEGMENTATION FAULT*/ 

void initialise(char flagarr[], long int n) //initialise all elements to true from 1 to n 
{ 
    long int i; 
    for (i = 1; i <= n; i++) 
     flagarr[i] = 't'; 
} 

void sieve(unsigned long long m, unsigned long long n, char seg_flags[]) 
{ 
    unsigned long long p, i, limit; 
    if (m == 1) 
     seg_flags[1] = 'f'; 
    /*Seperate inner loop for p=2 so that evens are not iterated*/ 
    for (i = 4; i >= m && i <= n; i += 2) 
    { 
     seg_flags[i-m+1] = 'f'; 
    } 
    if (seg_flags == flags) 
     limit = NEW_MAX; 
    else 
     limit = sqrt(n); 
    for (p = 3; p <= limit+1; p += 2) //initial p+=2 bcoz we need not check even 
    { 
     if (flags[p] == 't') 
     { 
      for (i = p*p; i >= m && i <= n; i += p) //start from p square since under it would have been cut 
      seg_flags[i-m+1] = 'f';   /*p*p, p*p+p, p*p + 2p are not primes*/ 
     } 
    } 
} 

void print_sieve(unsigned long long m,unsigned long long n,char flagarr[]) 
{ 
    unsigned long long i; 
    if (flags == flagarr) //print non-segented sieve 
    { 
     for (i = m; i <= n; i++) 
      if (flagarr[i] == 't') 
       printf("%llu\n", i); 
    } 
    else 
    { 
     //print segmented 
     for (i = m; i <= n; i++) 
      if (flagarr[i-m+1] == 't') 
       printf("%llu\n", i); 
    } 
} 

int main() 
{ 
    unsigned long long m, n; 
    int t; 
    char seg_flags[MAX_WIDTH+100]; 
    /*setting of flags for prime nos. by sieve of erasthromas upto NEW_MAX*/ 
    initialise(flags, NEW_MAX); 
    flags[1] = 'f'; /*1 is not prime*/ 
    sieve(1, NEW_MAX, flags); 
    /*end of initial sieving*/ 
    scanf("%d", &t); 
    while (t--) 
    { 
     scanf("%llu %llu", &m, &n); 
     if (n <= NEW_MAX) 
      print_sieve(m, n, flags); //NO SEGMENTED SIEVING NECESSARY 
     else if (m > NEW_MAX) 
     { 
      initialise(seg_flags, n-m+1); //segmented sieving necessary 
      sieve(m, n, seg_flags); 
      print_sieve(m, n, seg_flags); 
     } 
     else if (m <= NEW_MAX && n > NEW_MAX) //PARTIAL SEGMENTED SIEVING NECESSARY 
     { 
      print_sieve(m, NEW_MAX, flags); 
      /*now lower bound for seg sieving is new_max+1*/ 
      initialise(seg_flags, n-NEW_MAX); 
      sieve(NEW_MAX+1, n, seg_flags); 
      print_sieve(NEW_MAX+1, n, seg_flags); 
     } 
     putchar('\n'); 
    } 
    system("pause"); 
    return 0; 
} 

アップデート:ここでは、関連するテストケースとコードへのリンクです。

/*segmented sieve*/ 
#include<math.h> 
#include<stdio.h> 
#include<stdlib.h> 
#define MAX_LIMIT 1000000000 /*10^9*/ 
#define NEW_MAX 31623 /*SQUARE ROOT OF 1000000000*/ 
#define MAX_WIDTH 100000 /*10^5*/ 
int flags[NEW_MAX+1]; /*TO PREVENT SEGMENTATION FAULT goblal so initialised to 0,true*/  

void initialise(int flagarr[],long int n) 
/*initialise all elements to true from 1 to n*/ 
{ 
    long int i; 
    for(i=3;i<=n;i+=2) 
     flagarr[i]=0; 
} 

void sieve(unsigned long m,unsigned long n,int seg_flags[]) 
{ 

    unsigned long p,i,limit; 

    /*Seperate inner loop for p=2 so that evens are not iterated*/ 
    if(m%2==0) 
     i=m; 
    else 
     i=m+1; 
    /*i is now next even > m*/ 
    for(;i<=n;i+=2) 
    { 

     seg_flags[i-m+1]=1; 

    } 
    if(seg_flags==flags) 
     limit=NEW_MAX; 
    else 
     limit=sqrt(n); 
    for(p=3;p<=limit+1;p+=2) /*initial p+=2 bcoz we need not check even*/ 
    { 
     if(flags[p]==0) 
     { 


      for(i=p*p; i<=n ;i+=p) 
      /*start from p square since under it would have been cut*/ 
      { 
       if(i<m) 
        continue; 
       seg_flags[i-m+1]=1; 
        /*p*p, p*p+p, p*p + 2p are not primes*/ 

      } 
     } 
    } 
} 

void print_sieve(unsigned long m,unsigned long n,int flagarr[]) 
{ 
    unsigned long i; 
    if(m<3) 
    {printf("2\n");m=3;} 
    if(m%2==0) 
     i=m+1; 
    else 
     i=m; 
if(flags==flagarr) /*print non-segented sieve*/ 
{ 
    for(;i<=n;i+=2) 
     if(flagarr[i]==0) 
       printf("%lu\n",i); 
} 
else { 
//print segmented 

    for(;i<=n;i+=2) 
     if(flagarr[i-m+1]==0) 
       printf("%lu\n",i); 
}} 

int main() 
{ 
    unsigned long m,n; 
    int t; 
    int seg_flags[MAX_WIDTH+100]; 
    /*setting of flags for prime nos. by sieve of erasthromas upto NEW_MAX*/ 
    sieve(1,NEW_MAX,flags); 
    /*end of initial sieving*/ 
    scanf("%d",&t); 
    while(t--) 
    { 
     scanf("%lu %lu",&m,&n); 
     if(n<=NEW_MAX) 
      print_sieve(m,n,flags); 
      /*NO SEGMENTED SIEVING NECESSARY*/ 
     else if(m>NEW_MAX) 
     { 
      initialise(seg_flags,n-m+1); 
      /*segmented sieving necessary*/ 
      sieve(m,n,seg_flags); 
      print_sieve(m,n,seg_flags); 
     } 
     else if(m<=NEW_MAX && n>NEW_MAX) 
     /*PARTIAL SEGMENTED SIEVING NECESSARY*/ 
     { 
      print_sieve(m,NEW_MAX,flags); 
      /*now lower bound for seg sieving is new_max+1*/ 
      initialise(seg_flags,n-NEW_MAX); 
      sieve(NEW_MAX+1,n,seg_flags); 
      print_sieve(NEW_MAX+1,n,seg_flags); 
     } 
     putchar('\n'); 
    } 
    system("pause"); 
    return 0; 
} 

が、以下にさらに他の提案ウル考慮に入れて、私のふるい機能は、不正の出力を生成します - - :私はウルの提案の一部を実装し、私のコードは、正しい出力を生成

void sieve(unsigned long m,unsigned long n,int seg_flags[]) 
{ 

     unsigned long p,i,limit; 
     p=sqrt(m); 
     while(flags[p]!=0) 
       p++; 
     /*we thus get the starting prime, the first prime>sqrt(m)*/ 

     if(seg_flags==flags) 
       limit=NEW_MAX; 
     else 
       limit=sqrt(n); 
     for(;p<=limit+1;p++) /*initial p+=2 bcoz we need not check even*/ 
     { 
       if(flags[p]==0) 
       { 
         if(m%p==0) /*to find first multiple of p>=m*/ 
           i=m; 
         else 
           i=(m/p+1)*p; 

         for(; i<=n ;i+=p) 
         /*start from p square since under it would have been cut*/ 
         { 

           seg_flags[i-m+1]=1;  
             /*p*p, p*p+p, p*p + 2p are not primes*/ 

         } 
       } 
     } 
} 
+1

は、コードを選択&はCtrl-K –

答えて

2

あなたの問題は

です
for (i = 4; i >= m && i <= n; i += 2) 
for (i = p*p; i >= m && i <= n; i += p) 

範囲の下限が4以下の場合は、2の倍数を除外するだけで、より大きい素数の倍数を排除するだけです。ループ状態からi >= m部分を削除し、ループ本体内のif (i < m) { continue; }に置き換えます(より良い場合は、の最初の倍数をm以上に直接計算し、完全にその状態を避けてください)。

フラグとして't''f'を使用する代わりに、10をDMR用に使用してください。これはよく理解できます。

再更新:m == 2場合は、この

/*Seperate inner loop for p=2 so that evens are not iterated*/ 
if(m%2==0) 
    i=m; 
else 
    i=m+1; 
/*i is now next even > m*/ 
for(;i<=n;i+=2) 

はあなたを傷つけるでしょう。 m == 2の場合は、i = 4で始まる必要があります。あなたが小さな素数の倍数を排除する必要はないという意味ではありません、それはあなたの最初のバージョンということを意味しますが、私を誤解「とだけsqrt(m)より大きな素数の倍数をなくす」と思われる

unsigned long p,i,limit; 
p=sqrt(m); 
while(flags[p]!=0) 
    p++; 
/* snip */ 
for(;p<=limit+1;p++) 

に関する

その結果、この範囲のほとんどすべての数字が排除されませんでした。 p = 2で外側ループを開始するか、2の倍数に別のパスを入れて3でループを開始し、pを2だけインクリメントし、内側ループをp*pの大きい方から開始し、pの最小倍数m。後者の作品のためのあなたのコードは、その(あなたが少し速く枝を回避し、唯一の部門を使用してそれを作ることができますが、差は非常に小さいだろう)うまくいく

if ((i = p*p) < m) { 
    /* set i to smallest multiple of p which is >= m */ 
} 

でそれを包みます。

最後に、あなたは0と1で何を表しているかのあなたの選択は非常に0が条件とtrueに他のすべてにfalseと評価され、その標準的な交換が't' -> 1'f' -> 0などの状況であったであろう、これはCで、uncanonicalですその0と1が完全に罰金char値であり、配列エントリはフラグで、1は

if (flags[p]) // instead of: if (flags[p] != 0) 
if (!flags[p]) // instead of: if (flags[p] == 0) 

をチェックする場所これは、またchar[]からint[]に配列型を変更する必要は、ありませんcharはあまりにも整数型です。配列の型の選択には、パフォーマンスに影響があります。一方では、intサイズのロードとストアは通常、バイトサイズより高速です。したがって、ワードサイズの読み込みと書き込みには、さらにはlong int flags[]が好ましいでしょう。一方、小さいchar flags[]では、キャッシュのローカリティが向上します。 1つのフラグにつき1ビットを使用することで、より良いキャッシュローカリティを得ることができますが、それによって読み込み/設定/クリアフラグがさらに遅くなります。最良の性能をもたらすものは、ふるいの構造とサイズに依存します。

+0

ありがとうを使用し、plsは上記の私の質問の編集を参照してください! – ksb

+0

それに応じて回答が更新されました。 –

+1

すごく助けてくれてありがとう、最後にac @ spojを手に入れました。 – ksb

関連する問題