質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

4005閲覧

C言語でアトキンの篩を実装したい〈初心者〉

Nishiki

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

1グッド

1クリップ

投稿2019/05/21 08:35

編集2019/05/21 10:27

この春から大学でプログラムを学び始めた者です。
講義にて、素数の演算と表示に関する話がありました。
その中で、エラトステネスの篩とアトキンの篩について紹介があり、どちらの方がどのくらい早いのかと、入力した数以下の素数と処理時間を表示するものを組もうとしています。
しかし、エラトステネスの篩は出来たのですが、アトキンの篩が上手いこと組めずにいます。
そこで、ネットから参考となるコードを探したのですが、C言語で記述されたものを見つけることができませんでした。
次に、C++のコードをC言語に出来ないかと試み、エラーは消えたのですが、知識が足りないためギャップを埋めきれなかったようで、前述した素数と処理時間の表示という動作をしませんでした。(素数が表示されず処理時間のみ表示される)
どう違っているのか教えて下さい!

該当のソースコード

C

1#include <stdio.h> 2#include <math.h> 3#include <sys/time.h> 4 5#define M 1000 6#define true 1 7#define false 0 8 9int main(){ 10 struct timeval s, e; 11 gettimeofday(&s, NULL); 12 13 /*process*/ 14 void atkin() { 15 int n,z,y,x,k; 16 double N = 1000; 17 int isprime[200]; 18 for (z = 1; z <= 5; z += 4) { 19 for (y = z; y <= sqrt(N); y += 6) { 20 for (x = 1; x <= sqrt(N) && (n = 4*x*x+y*y) <= M; ++x) 21 isprime[n] = !isprime[n]; 22 for (x = y+1; x <= sqrt(N) && (n = 3*x*x-y*y) <= M; x += 2) 23 isprime[n] = !isprime[n]; 24 } 25 } 26 for (z = 2; z <= 4; z += 2) { 27 for (y = z; y <= sqrt(N); y += 6) { 28 for (x = 1; x <= sqrt(N) && (n = 3*x*x+y*y) <= M; x += 2) 29 isprime[n] = !isprime[n]; 30 for (x = y+1; x <= sqrt(N) && (n = 3*x*x-y*y) <= M; x += 2) 31 isprime[n] = !isprime[n]; 32 } 33 } 34 for (y = 3; y <= sqrt(N); y += 6) { 35 for (z = 1; z <= 2; ++z) { 36 for (x = z; x <= sqrt(N) && (n = 4*x*x+y*y) <= M; x += 3) 37 isprime[n] = !isprime[n]; 38 } 39 } 40 for (n = 5; n <= sqrt(N); ++n) 41 if (isprime[n]) 42 for (k = n*n; k <= M; k+=n*n) 43 isprime[k] = false; 44 isprime[2] = isprime[3] = true; 45} 46 47 gettimeofday(&e, NULL); 48 printf("time = %lf\n", (e.tv_sec - s.tv_sec) + (e.tv_usec - s.tv_usec)*1.0E-6); 49 return 0; 50} 51

参考にしたサイト

時間の計測
アトキンの篩のやり方
アトキンの篩
アトキンの篩
C言語のtrueとfalseについて
C++の記号一覧

補足情報(FW/ツールのバージョンなど)

Oracle VM VirtualBox
Oracle VM VirtualBox Extension Pack
Cent OS 7
C99以前

set0gut1👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2019/05/21 08:57

URL を「リンクの挿入」での記述に編集して頂けると, クリックで飛べるようになります. > 思った通りの動作をしませんでした どう思ったのにどう動作したのでしょうか. その原因はどこまで追跡されていますでしょうか.
cateye

2019/05/21 08:58

最適化されれば消えるかもですが、sqrt(N)は先に求めておいた方がいいのでは?
moredeep

2019/05/21 09:05

配列を初期化していないせいな気がします。(自信0)
cateye

2019/05/21 09:16 編集

>思った通りの動作・・・とは? 素数の数が合わないとかでしょうか?
guest

回答2

0

ベストアンサー

まずは関数の定義など基本的な文法から学び直してください。
また、定義に立ち返ってアルゴリズムをしっかり確認してみてください。

処理が複雑なら分解して関数化する、スコープを小さくして間違いにくくする、というのも手です。

具体的に何が問題か指摘するのが大変なので、以下にアトキンの篩のコードを書いておきます。

c

1#include <stdio.h> 2 3#define N 1000000 4#define TRUE 1 5#define FALSE 0 6 7int is_in(int num, int set[], int length) { 8 for(int i = 0; i < length; i++) { 9 if(num == set[i]) return TRUE; 10 } 11 return FALSE; 12} 13 14void toggle(int* target) { 15 if(*target == TRUE) { 16 *target = FALSE; 17 } 18 *target = TRUE; 19} 20 21void step1(int is_prime[]) { 22 int n, n60; 23 int s[] = {1,13,17,29,37,41,49,53}; 24 int s_len = sizeof(s) / sizeof(s[0]); 25 26 for(int x = 1; 4 * x * x < N; x++) { 27 for(int y = 1; y < N; y = y + 2) { 28 n = 4 * x * x + y * y; 29 if (n > N) break; 30 n60 = n % 60; 31 if(is_in(n60, s, s_len) == TRUE) { 32 toggle(is_prime + n); 33 } 34 } 35 } 36} 37 38void step2(int is_prime[]) { 39 int n, n60; 40 int s[] = {7,19,31,43}; 41 int s_len = sizeof(s) / sizeof(s[0]); 42 43 for(int x = 1; 3 * x * x < N; x = x + 2) { 44 for(int y = 2; y < N; y = y + 2) { 45 n = 3 * x * x + y * y; 46 if (n > N) break; 47 n60 = n % 60; 48 if(is_in(n60, s, s_len) == TRUE) { 49 toggle(is_prime + n); 50 } 51 } 52 } 53} 54 55void step3(int is_prime[]) { 56 int n, n60; 57 int s[] = {11,23,47,59}; 58 int s_len = sizeof(s) / sizeof(s[0]); 59 60 for(int x = 2; 3 * x * x < N; x++) { 61 for(int y = x - 1; y > 0; y = y - 2) { 62 n = 3 * x * x - y * y; 63 if (n > N) break; 64 n60 = n % 60; 65 if(is_in(n60, s, s_len) == TRUE) { 66 toggle(is_prime + n); 67 } 68 } 69 } 70} 71 72void eliminate_composites(int is_prime[]) { 73 int s[] = {1,7,11,13,17,19,23,29,31,37,41,43,47,49,53,59}; 74 int s_len = sizeof(s) / sizeof(s[0]); 75 int n; 76 77 for(n = 7; n*n < N; n++) { 78 if( is_in(n % 60, s, s_len) == TRUE && is_prime[n] == TRUE) { 79 for(int i = 1; i < N/(n*n); i++) 80 is_prime[n*n*i] = FALSE; 81 } 82 } 83} 84 85 86int main(int argc, char* argv[]) { 87 int is_prime[N+1] = {FALSE}; 88 89 step1(is_prime); 90 step2(is_prime); 91 step3(is_prime); 92 eliminate_composites(is_prime); 93 94 printf("2\n3\n5\n"); 95 for(int n = 7; n <= N; n++) { 96 if(is_prime[n] == TRUE) 97 printf("%d\n", n); 98 } 99 100 return 0; 101}

投稿2019/05/21 10:23

編集2019/05/22 05:31
mather

総合スコア6753

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ざっとみて(処理の正当性は別として)

1.main() の中に void atkin() の定義を内包しているのは誤りなので main() の外に atkin() の定義内容を全部追い出してください。

2.atkin() の中で int isprime[200]; と宣言してありますが、atkin() の中で isprime[] にアクセスするnやkの値が200以上になる事がありメモリを破壊しそうです。
(これくらいの大きさならほとんどの環境で大丈夫だとは思いますが関数内であまりにも巨大すぎる配列をオート変数として確保するとスタックを破壊するリスクもあるので大きめな配列を確保するのならグローバル変数にしてしまう方がいいかもしれません)

3.isprime配列を初期化せずに参照しているので先に初期化しておくと良いかもしれません(ローカル変数は初期値不定です)

投稿2019/05/21 09:16

HiroshiWatanabe

総合スコア2160

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問