• ベストアンサー

bool

素数を求めるプログラムを作りました。 素数か、そうでないかを1か0で区別していたのですが、 よりメモリを効率よく使いたいため、booleanを使ったらどうだという案をいただきやってみたのですが、エラーが出てしまいました。 このプログラムの何がいけないのですか? #include<stdio.h> #include<stdbool.h> #define n 250000 main(){ int i,p,k,w,np,s; bool pn[n]; np=0; for(i=0;i<n;i++){ pn[i]=false; } for(i=0;i<=n;i++){ if(pn[i]==false){ p=3*i+5-(i%2); w=2*p; for(k=i+w;k<=n;k+=w){ pn[k]=true; } s=5*i+7-2*(i%2); for(k=s;k<n;k+=w){ pn[k]=true; } np++; } } printf("%10d",np+2); }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

ご説明ありがとうございます。 どういう意図で組まれたのかようやく納得できました。 が、当方そこまでの理解力が無かったので、純粋にp=iの関係と考えて素数が求まっているように見えなかったというだけです。2の倍数・3の倍数を抜いて計算するという考え方は正しいと思います。(私も以前に2の倍数を除いたエラトステネスの篩なら組んだ事があります。懸賞問題向けだったのですがエラトステネスの篩での応募多数のため予め2の倍数を除いたものは「素数の計算を一部省略している」という理由で不正解とされた不本意な結果でしたが。) 残念ながら、作成されたプログラムのアルゴリズムが正しいか否かは私にはすぐには判断できません。 ただ、少なくとも配列pnの範囲をオーバーしたアクセスがあるのは確かなのでpnを1つ大きく作成するか、for 終端条件の見直しは必要かと思います。

その他の回答 (4)

回答No.4

まず、他の方も答えていますが bool は一般的なコンパイラは int 等で実装されているため余り記憶領域の節約にはなりません。No.2の方のようにビットマップを使うべきでしょう。 あと、上記プログラムは上から3番目のforの停止条件がk<=nとなっていて、k=nとなるケースがあり配列pn[n]の領域外アクセスが発生してしまいます。k<nとすべきです。 ただ、上記プログラムを修正したとしても素数を求めているようには思えませんし結果も間違ってます。エラトステネスの篩(ふるい)的なアプローチのようにも見えますがどうなのでしょうか?(エラトステネスの篩になるよう改造してみましたがここに出してしまうとご本人の勉強にならないと思いますので伏せておきます。)

monkey-bridge
質問者

補足

エラトステネスの篩の応用バージョンのつもりです。 エラトステネスの篩で、予め2と3の倍数をぬいてしまい、篩にかけることで、メモリ使用率を減らそうという目的でつくりました。 まず、添え字iと、対応する自然数pの関係を考える。 普通に考えた時のプログラムでは、p=i、 2の倍数だけを除いたプログラムではp=2*i+3の関係があった。 2,3の倍数を除いたプログラムでは・・・ 添え字i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 自然数p 5 7 11 13 17 19 23 25 29 31 35 37 41 43 47 49 添え字iが偶数(0も含む)の時は  p=3*i+5 添え字iが奇数の時は        p=3*i+4   の関係があることがわかる。さらに、「iが偶数の時0、奇数の時1になる式」(i%2)を使って、p=3*i+5-(i%2)でまとめられる。 次に、倍数を消していく作業について考える。 添え字iが偶数の時、奇数の時をそれぞれ別々の数列で考えると、どちらも公差6の等差数列になっていることがわかる。 iが偶数 5 11 17 23 29 35 41 47 53 iが奇数 7 13 19 25 31 37 43 49 そこで、例えば5の倍数を消していく作業について考えると、偶数数列においては5から始めて5番目ごとが5の倍数になっているのでそれらを消せばよいことがわかる。つまり、実際(奇数偶数を分けないで考える)は、2×5=10ごとに消せばいいことがわかる。奇数数列においては、最初に5の倍数がでてくる、25から始めれば良い。この25という数字はs=5*i+7-2*(i%2)で求められる(この式については最後に述べる)。 つまり、pから始めて2*pごと、s=5*i+7-2*(i%2)から始めて2*pごとに消していくことにより、倍数を消していく作業が完了する。 3、 プログラムについて 1) pn[i]すべてに1をいれる 2) i=0から指定された数を超えるまで以下の作業を繰り返す  2-1)pn[i]の値が1ならば、iに対応する自然数pは素数であるので    A)pは残して2*p以降、2*pごとにpn[i]の値に0を入れる    B)Sから始めて、2*pごとにpn[i]の値に0を入れる  2-2)pn[i]の値が0ならば、iの値を1増やす 4、 補足s=5*i+7-2*(i%2)について 2と同様「5」を例にとって考える。まず、5自身は偶数の数列にいるので、偶数の数列において5ずつ消していけば、5の倍数は消えていった。次に奇数数列の25については、このプログラム自身が2と3の倍数を抜いて考えているのだから、5×2=10(2の倍数)、5×3=15(3の倍数)、5×4=20(2の倍数)は現れないはずである。よって5×5=25が最小であることがわかる。ここで疑問に思うのが、pと5*pとは添え字の奇数・偶数が必ず異なるのか?ということである。 しかし、実際に5を例にとって考えると、5と25の添え字の奇数・偶数は異なっている。幸い、pと5*pとは添え字の奇数・偶数が必ず異なることが証明できるのである。 一般に、添え字iが偶数である自然数pはp=3*i+5=3*(2*h)+5=6*(h+1)-1という形で表せ、 また、添え字iが奇数である自然数pはp=3*i+4=3*(2*h+1)+4=6*(h+1)+1という形で表すことが出来る。 ここで、添え字iが偶数である自然数pについては、5*p=(6-1)(6*(h+1)-1)=6(5(h+!)-1)+1となり、5*pにあたる添え字iは奇数であることが証明できた。 また、添え字iが奇数である自然数pについては、5*p=(6-1)(6*(h+1)+1)=6(5(h+!)-1)-1 となり、5*pにあたる添え字は偶数であることが証明できた。 以上により、pと5*pとは添え字の奇数・偶数が必ず異なることが証明できた。 よって、同じ系列の出発点にはp自身、別の系列の出発点には、5*pが使える。 しかし、pや5*pは対応する自然数の値であって添え字の値ではない。 ここで5*pの添え字sについて考えるP=3*i+5-(i%2)より 5*p=5(3*i+5-(i%2))=3*(5*i+7-2*(i%2))+5-(1-(i%2)) =3*(5*i+7-2*(i%2))+5-(s%2) (s%2)=1-(i%2)より よって、s=5*i+7-2*(i%2)とおけば、5*p=3*s+5-(s%2)が成り立つ。 ・・・という考えのもとこのプログラムをつくったのですが、考え方が根本的にまちがっているのでしょうか?

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.3

素数がまったく判定できていないような気がするのは私だけでしょうか?

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★『stdbool.h』では『_Bool』が予約語です。 ・『bool』は予約語ではないのでエラーになったと思います。  また C99 に対応しているコンパイラなら stdbool.h はありますが未対応なら  ヘッダはないのでこれまたエラーなります。  どんなコンパイラを使っているのか分かりませんがこのことを頭の片隅に  置いておいて下さい。 >よりメモリを効率よく使いたいため…  ↑  それなら『ユークリッドの互除法』で計算させる方法もあります。  http://www2.cc.niigata-u.ac.jp/~takeuchi/tbasic/BackGround/Euclid.html  ネットで検索するといろいろ見つかります。  また『_Bool』型を使ってもメモリ効率が良くなるかは分かりません。  言語仕様では 0、1 を記憶できれば良いだけで _Bool 型が 1 ビットの領域で  管理されるかは分かりません。0、1 で管理させたいならビット演算すれば良い。 ・下にサンプルを載せます。 サンプル: // ビット調査 int GetBool( unsigned char bool[], int no ) {  return (bool[ no >> 3 ] & (1 << (no & 0x7))) ? 1 : 0; } // ビット・セット void SetBool( unsigned char bool[], int no ) {  bool[ no >> 3 ] |= (1 << (no & 0x7)); } // ビット・リセット void ResetBool( unsigned char bool[], int no ) {  bool[ no >> 3 ] &= ~(1 << (no & 0x7)); } 使い方: int main( void ) {  unsigned char BoolTable[ 100 ]; // 800 ビット管理可能    SetBool( BoolTable, 123 ); // 123 番目のビットをON    ResetBool( BoolTable, 456 ); // 456 番目のビットをOFF    if ( GetBool(BoolTable,753) ){ // 753 番目のビットを調査   // 753 番目のビットは ON  }  else{   // 753 番目のビットは OFF  }  return 0; } 以上。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

> エラーが出てしまいました。 何をしたときに、どんなエラーが出ましたか? エラーメッセージの内容を、正確に提示してください。

monkey-bridge
質問者

補足

インクルードファイル 'stdbool.h' をオープンできない と出ました。

関連するQ&A

  • 配列に順列を入れ、その順列を使いルール通りの組合せを作るには

    配列nを用意して、2*nの配列に1~Z、又は1~9までの数字を格納します。3の場合、123,132,213,231,312,321の順列で、ルールは1の時は1つ間を空けて1を、2の時は2つ間を空けて2を・・・ つまり、3の場合は 231213,312132 の二つがルールと合致しているので答えとなります。 1~Zまでで、上記のようにルールに当てはまる場合のみを出力するプログラムを書きたいのですがうまくいきません。下に考えてみたものを載せます。どなたか分かる方ご教授願います。 #include<stdio.h> int p[99]={0},a[99]={0}; int n; int count; main(){ int i; void perm(int k); while(1){ scanf("%d",&n); if(n<=0){break;} for(i=1;i<=n;i++){p[i]=i;} count=0; perm(1); } } void perm(int k){ int i,w; if(k>n){ count++; for(i=1;i<=n;i++){a[i]=p[i];} for(i=1;i<=n;i++){a[i+a[i]+1]=a[i];} printf("[%d]:",count); for(i=1;i<=2*n;i++){printf("%3d",a[i]);} printf("\n"); } else{ for(i=k;i<=n;i++){ w=p[k];p[k]=p[i];p[i]=w; perm(k+1); w=p[k];p[k]=p[i];p[i]=w; } } }

  • 掃出法で連立一次方程式の解を求める

    掃出法で連立一次方程式の解を求めるプログラムを作ってみたのですが、ポインタと浮動小数点のエラーが出てしまい、実行できません。どこが間違っているのかさえ分からず困っています。訂正箇所を教えてください。宜しくお願い致します。 #include<stdio.h> #include<math.h> #include <float.h> #define N 3 #define EPSILON 1.0E-5 #define TRUE 1 #define FALSE 0 void sweep(int *flag); void swap(float *wk1,float *wk2); float a[N][N]={{ 2, 6, 3}, {-1, 5,-2}, {-2,-1, 6}}; float x[N],b[N]={6,3,14}; int flag; void main() { int i,j; for(i=0;i<N;i++) { for(j=0;j<N;j++) printf("%10.4f",a[i][j]); printf("%10.4f\n",b[i]); } flag=TRUE; sweep(&flag); if(flag==TRUE) { printf("連立方程式の解\n"); for(i=0;i=N;i++) printf("x[%d]=%10.4f\n",i+1,x[i]); } else printf("解なし\n"); } void swap(float *wk1,float *wk2) { float w; w=*wk1; *wk1=*wk2; *wk2=w; } void sweep(int *flag) { int i,j,k,ik; float ak,aik; for(k=0;k<N;k++) { ak=a[k][k]; if(fabs(ak)<=EPSILON) { ik=k+1; while((ik<N)&&(fabs(a[ik][k])<EPSILON)) ik++; if(ik<N) { for(j=k;j<N;j++) swap(&a[k][j],&a[ik][j]); swap(b[k],b[ik]); ak=a[k][k]; } else { printf("ピボットが零です\n"); *flag=FALSE; goto end; } } for(j=k;j<N;j++) a[k][j]=a[k][j]/ak; b[k]=b[k]/ak; for(i=0;i<N;i++) { if(i!=k) { aik=a[i][k]; for(j=k;j<N;j++) a[k][j]=a[i][j]-aik*a[k][j]; b[i]=b[i]-aik*b[k]; } } for(k=0;k<N;k++) x[k]=b[k]; end:; } }

  • C言語のプログラムで質問です。

    C言語のプログラムで質問です。 これは、2元1次連立方程式の解を求めるプログラムです。 このプログラムを (1)3元1次連立方程式の解を求めるプログラムにする (2)係数行列、定数行列(6、7行目)をキーボードからの入力にする。 ようにしたいのですが、どうすればよいでしょうか。 前半の部分を変えれば良いようなのですが分かりません。教えてください。 #include <stdio.h> #include <math.h> /* gauss22.c */ #define N 2 main(){ double A[N][N]={1.,4.,3.,2.}, Aa[N][N]; /*簡単のため係数行列を予め指定*/ double b[N]={4.,5.}, x[N], bb[N], e[N]; /*簡単のため定数ベクトルを予め指定*/ int n=2; int i, j, k; double akk, aik, s; /* save original coefficients */ for (i=0; i<n; i++){ for (j=0; j<n; j++){ Aa[i][j]=A[i][j]; } bb[i]=b[i]; } /* forward operation */ for (k=0; k<n-1; k++){ akk=1/A[k][k]; for (i=k+1; i<n; i++){ aik=-A[i][k]*akk; for (j=k+1; j<n; j++){ A[i][j]+=aik*A[k][j]; } b[i]+=aik*b[k]; } for (j=k+1; j<n; j++){ A[k][j]*=akk; } b[k]*=akk; } /* backward operation */ x[n-1]=b[n-1]/A[n-1][n-1]; for (k=n-2; k>=0; k--){ s=0.0; for (j=k+1; j<n; j++){ s+=A[k][j]*x[j]; } x[k]=b[k]-s; } /* chek */ for (i=0; i<n; i++){ s=0.0; for (j=0; j<n; j++){ s+=Aa[i][j]*x[j];} e[i]=s-bb[i]; printf("x(%d)=%f error=%f?n",i, x[i], e[i]); } }

  • 正しい結果が表示されない

    以下のプログラムはガウスの消去法を使って 解を求めるプログラムです。 しかし、gauss関数にprintf関数を入れてコンパイルすると 正しい結果 5 3 1 0 0 がでますが、gauss関数にprintf関数をいれずmain関数に書くと 0 0 0 0 0 となります。 なぜでしょうjか?? #include<stdio.h> #include<math.h> #define N 5 void gauss(double a[N][N+1]); int main(){ double a[N][N+1] = { { 1,-1,-1,-1,-1, 1}, {-1, 1,-1,-1,-1,-3}, {-1,-1, 1,-1,-1,-7}, {-1,-1,-1, 1,-1,-9}, {-1,-1,-1,-1, 1,-9} }; double x[N]; int i; gauss(a); printf("\n[x]=\n"); /* x[i] を表示する */ for(i=0; i<N; i++){ printf(" %8.3lf\n", x[i]); } return(0); } void gauss(double a[N][N+1]) { int i,j,k,p; double m, pmax, s, x[N]; for(k = 0; k < N-1; k++){ /* ピボット操作 */ p = k; /* p, pmax の初期値 */ pmax = fabs(a[k][k]); for(i = k+1; i < N; i++){ /* 最大値を検索 */ if(fabs(a[i][k]) > pmax){ p = i; pmax = fabs(a[i][k]); } } if(fabs(pmax) < 1.0e-12){ /* 最大値がゼロに近い時はエラー */ fprintf(stderr, "too small pivot!\n"); exit(1); } if(p != k){ /* ピボット操作 */ for(j = 0; j < N+1; j++) { s = a[k][j]; /* 値の入れ替え */ a[k][j] = a[p][j]; a[p][j] = s; } } for(i = k+1; i < N; i++) { /* 第 i 行 */ m = a[i][k] / a[k][k]; /* 倍率 m を計算 */ a[i][k] = 0; /* 注1 (下記参照) */ for(j = k+1; j < N+1; j++) { /* 第 j 列 */ a[i][j] = a[i][j] - a[k][j] * m; } } } for(i = N-1; i >= 0; i--){ /* 後退代入 */ m = 0; for(j = N-1; j > i; j--){ m = m + a[i][j] * x[j]; } x[i] = (a[i][N] - m) / a[i][i]; } }

  • C言語の配列の宣言について

    20年以上前に発行された本に書いてある、利用したいCのコードがあります。 JavaやPHPは使ったことがありますが、Cは触ったことすらありません。 とりあえずメモ帳に打ち出して、codepadでC codeで実行してみましたが、正常に動作しません。 どこがおかしいのか、ご教示ください。 よろしくお願いします。 ---- #include <stdio.h> #include <math.h> #define N 20; int main( int argc, char **argv ) { double u[N+1], w[N+1]; double k=0.001; double h, r, s; int i, j; h= 1.0/(double)N; r= k/(h*h); s= 1.0-2.0*r; for( i=0; i<=N; i++ ) w[i]=0.0; for( i=1; i<N; i++ ) u[i]=1.0; u[0]=0.0; u[N]=0.0; for(j=1;j<200;j++){ if((j%10)==0) { printf("%5.31f",(double)j*k); for(i=0;i<=N;i+=2) printf("%5.31f",u[i]); printf("\n"); } for( i=0; i<=w; i++ ) w[i]=r*(u[i+1]+u[i-1])+s*u[i]; for( i=1; i<N; i++ ) u[i]=w[i]; } return 0; }

  • for文の条件式について

    #include<stdio.h> #define N 30 #define TRUE 1 #define FALSE 0 char is_prime[N+1]; int main(void) { for(i=1;i<=N;i++){ is_prime[i]=TRUE; } is_prime[1]=FALSE for(i=2;i*i<=N;i++)→(1) if(is_prime[i]) for(j=i*2;j<=N;j+=i)→(2) is_prime[j]=FALSE;→(3) printf("%dまでの素数は、\n",N); for(i=1;i<=N;i++) if(is_prime[i]) printf("%d",i); return 0; これはエラトステネスの素数を求めるプログラムですが、(1)のi*iは2 3 5と理解できるんですが(2)の条件式が理解できません。 例えはi=2のときjは4になるのですが、(3)は is_prime[4]=FALSEとなりj+=iは6になりますが、何ゆえこれが増分として出てくるのか理解できません。 j+=iはどういう使われ方をするのか理解できません。どなたかご教授ねがいます。

  • C言語についての質問です。

    C言語についての質問です。 このプログラムの前半にある A[N][N]={{1,0,0},{0,1,0},{0,0,1}} b[N]={4,5,3} という行列の成分をキーボードから入力するようにする にはどうすればいいでしょうか。 for や scanf や printf を使って、変えてくれないでしょうか。 #include <stdio.h> #include <math.h> /* gauss33.c */ #define N 3 main(){ double A[N][N]={{1,0,0},{0,1,0},{0,0,1}}; double b[N]={4,5,3}; double Aa[N][N]; double x[N], bb[N], e[N]; int n=N; int i, j, k; double akk, aik, s; /* input original coefficients */ /* save original coefficients */ for(i=0; i<n; i++){ for(j=0; j<n; j++){ Aa[i][j]=A[i][j]; } bb[i]=b[i]; } /* forward operation */ for(k=0; k<n-1; k++){ akk=1/A[k][k]; for (i=k+1; i<n; i++){ aik=-A[i][k]*akk; for (j=k+1; j<n; j++){ A[i][j]+=aik*A[k][j]; } b[i]+=aik*b[k]; } for(j=k+1; j<n; j++){ A[k][j]*=akk; } b[k]*=akk; } /* backward operation */ x[n-1]=b[n-1]/A[n-1][n-1]; for(k=n-2; k>=0; k--){ s=0.0; for (j=k+1; j<n; j++){ s+=A[k][j]*x[j]; } x[k]=b[k]-s; } /* chek */ for(i=0; i<n; i++){ s=0.0; for(j=0; j<n; j++){ s+=Aa[i][j]*x[j];} e[i]=s-bb[i]; printf("\nx(%d)=%f error=%f\n",i, x[i], e[i]); } }

  • c言語 行列のn階乗のプログラム

      1 2 -1 D= 3 0 -2   -1 1 2 の3次正方行列のn乗を計算するプログラムを作成しています。 いろいろと試してみましたがうまくいきません。 どなたか教えていただけるとうれしいです。 よろしくおねがいします。 #include <stdio.h> int main(void) { int a[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int b[3][3]={ {-1,2,-1},{3,0,-2},{-1,1,2} }; int s[3][3]; int m,n; int i,j,k; printf("[A]^n;n = ");scanf("%d",&n); for (m=2;m <= n;m++){ for (i=0;i<3;i++){ for (j=0;j<3;j++){ s[i][j] = 0; for(k=0;k<3;k++){ s[i][j] =s[i][j] + a[i][k] * b[k][j]; } } } for(i=0;i<3;i++){ for(j=0;j<3;j++){ b[i][j]=s[i][j]; } } printf("%3d",s[i][j]); putchar('\n'); } return (0); }

  • n次元ベクトルの線型独立について。

    「3個のn次元ベクトルP1,P2,P3が線型独立なら、この内の2個のp1,p2も線型独立であることを証明せよ。」 Pnをn次元ベクトルとする。 P1(p11、p12、p13、・・・p1n) P2 (p21、p22、p23、・・・p2n) ・ ・ ・ Pn(pn1、pn2、pn3、・・・pnn) とする。 基底ベクトルを次のように定める。 i(1)、j(2)、k(3)、・・i(nー2)、j(n-1)、k(n) ベクトル外積P2XP3を次のように定める。 P2XP3 =|i(1)、  j(2)、 k(3) |  |p(21)、p(22)、p(23)|  |p(31)、p(32)、p(33)|  |i(4)、  j(5)、 k(6) | +|p(24)、p(25)、p(26)|  |p(34)、p(35)、p(36)| ・ ・ ・ ・  |i(n-2)、    j(n-1)、      k(n)| +|p(2、(n-2))、p(2、(n-1))、 p(2n)|  |p(3、(n-2))、p(3、(n-1))、p(3、n)| (と、n次元Vector外積を上記のようにしましたが これでよいのでしょうか?) とする時。 P1・(P2XP3)=C1 (C1はゼロでない) が成り立つとき、P1,P2,P3は一次独立である。 このとき (P2XP3)=C2  (C2はゼロVectorでないので。) が成り立つので、P2,P3は一次独立である。 故にP1,P2,P3が一次独立のとき 他の2個のVectorは一次独立となる。

  • カウンタ利用の再帰式

    下記に記述してあるプログラムを1~100までの2の倍数の和と積を求め、但し倍数の個数Nは、N=3に変えたいのですがどうすればいいのかわかりません。 どなたかご教授お願いします。 /* prog.c */ #include <stdio.h> #define N 5 main() { static int a[N]={1,2,3,4,5}; int S[N],P[N]; int i; a[0]=i; S[0]=a[0]; P[0]=a[0]; for(i=1;i<=(N-1);i++){ a[i]=i+1; S[i]=S[i-1]+a[i]; P[i]=P[i-1]*a[i]; } for(i=0;i<=(N-1);i++){ printf("i=%d,a[%d]=%d,S[%d]=%d,P[%d]=%d\n",i,i,a[i],i,S[i],i,P[i]); } }

専門家に質問してみよう