# eratosthenes篩法 c語言 ``` https://web.ntnu.edu.tw/~algo/Prime.html #include <stdio.h> //4 #include <math.h> #define N 100 //20000000 int sieve[N]={1,1}; // 1代表不是質數, 0代表是質數 void main() //eratosthenes { // 只需要刪掉sqrt(N)以下的質數的倍數。 for (int i=2; i<=sqrt(N); i++) if (!sieve[i]) // k是倍率,j是質數i的倍數。當k-1,j同時-i // 當sieve[k]不是質數時,不用再次設定sieve[j]一次。 // (k,j)=(5,15),(k,j)=(3,9) for (int k=N/i, j=i*k; k>=i; k--, j-=i){ if (!sieve[k]){ sieve[j] = 1; } } for (int i=2; i<=N; i++){ if (!sieve[i]) printf("%d ",i); } } // 運用小範圍的sieve[k],避免存取大範圍的sieve[j], // 大幅減少cache miss。 ``` # 使用 bitset 來取代 bool 陣列 ``` #include <stdio.h> //5 #include <math.h> #define N 100 //20000000 //一個 int 有 32 個位元,可以當作 32 個欄位來使用,節省記憶體空間,減少 cache miss 。 int sieve[(N>>5)+1]={1,1}; // 1代表不是質數, 0代表是質數 // inline關鍵字讓編譯器用「函式內容」覆蓋掉「函式呼叫」。 // https://www.greenend.org.uk/rjk/tech/inline.html static inline int GET(int x) { return sieve[x>>5]>>(x&31) & 1; } static inline void SET(int x) { sieve[x>>5] |= 1<<(x&31); } void main() //eratosthenes篩法 c語言 { // printf("%d\n",sizeof(sieve)/sizeof(int)); // register關鍵字讓變數存放於CPU register,加快存取速度。 register int i, j, k; for (i=2; i<=sqrt(N); i++) if (!GET(i)) for (k=N/i, j=i*k; k>=i; k--, j-=i) if (!GET(k)) SET(j); for (int i=2; i<=N; i++){ if (!GET(i)) printf("%d ",i); } } ``` # 不處理 2 的倍數 ``` //令陣列第 0 格代表數字1 、陣列第 1 格代表數字3 、陣列第 2 格代表數字5 、 …… ,以此類推。 #include <stdio.h> //6 #include <math.h> #define N 200 //1<<25,20000000 //const int N = 1<<7; //200; 1<<7 = 2^7 //一個 int 有 32 個位元,可以當作 32 個欄位來使用,節省記憶體空間,減少 cache miss 。 // 1代表不是質數, 0代表是質數 int sieve[(N>>6) + 1]; // 不處理2的倍數 #define GET(x) (sieve[x>>5]>>(x&31) & 1) #define SET(x) (sieve[x>>5] |= 1<<(x&31)) #define N2I(i) ((i-1)>>1) // 索引值 = (數字-1) / 2 #define I2N(i) ((i<<1)+1) // 數字 = 索引值*2 + 1 // 驗證一個數字是不是質數 int isprime(int x){ return x==2 || x>2 && (x&1) && !GET(N2I(x)); } void main() //eratosthenes篩法 c語言 { int half_sqrt_N = sqrt(N) / 2; int half_N = N >> 1; register int i, j, k, ii; // 從3開始。N2I(3) = 1。 for (i=1; i<=half_sqrt_N; i++) if (!GET(i)) // ii //for (j=2*i*(i+1), k=2*i+1; j<half_N; j+=k) // SET(j); for (ii=I2N(i), j=N2I(N/ii), k=ii*j+i; j>=i; j--, k-=ii) if (!GET(j)) SET(k); if (isprime(N)) half_N += 1; printf("%d ",2); for (i=1; i<half_N; i++) if (!GET(i)) printf("%d ",i*2+1); } ```