• ベストアンサー

動いているのに…

学校の課題で、 ランダム関数を使って、 πの近似値を求めようという課題が出されました。 そして、私は、 #include<stdio.h> #include<stdlib.h> double pai_calc(int n);//乱数を発生させて、近似値と求める int main(void){ int i,n;//nは発生させる乱数の数 for(i=0;i<=5;i++){ if(i==0) n=10; else if(i==1) n=100; else if(i==2) n=1000; else if(i==3) n=2000; else if(i==4) n=5000; else n=10000; printf("pai approx.[%d]=%f\n",n,pai_calc(n)); } return(0); } double pai_calc(int n){ double rndx,rndy,pai,m=0; int i; for(i=1;i<=n;i++){ rndx=(float)rand()/32768.0;//1以下の少数を発生させる rndy=(float)rand()/32768.0; if((rndx*rndx+rndy*rndy)<=1) m++; } pai=4*m/n; return(pai);} このように作って、結果も pai approx.[10]=3.200000 pai approx.[100]=3.280000 pai approx.[1000]=3.148000 pai approx.[2000]=3.148000 pai approx.[5000]=3.120800 pai approx.[10000]=3.139600 となったのですが、 先生のPC上では、 pai approx.[10]=0.000000 pai approx.[100]=0.000000 pai approx.[1000]=0.000000 pai approx.[2000]=0.000000 pai approx.[5000]=0.000000 pai approx.[10000]=0.000000 となるそうです。 (つまり失格とのこと) 私のパソコンでは、それぞれ近似値がでたのに、 どうしてでしょうか?? 理解できません。 また、1以下の少数を発生させるのに、 マジックナンバー32768.0を使うな といわれましたが、これを他の方法で置き換えることが できません。 初心者で、まことに申し訳ございませんが、 ご教授ください。

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

関数 rand() の仕様は確認しましたか? 関数 rand() は「0 と RAND_MAX の間の値」を返します. この RAND_MAX は「少なくとも 32767」と決まっているだけなので, 実際の値は処理系に依存します. 従って, RAND_MAX が大きな処理系で計算すると pai_calc の中の if の条件はほとんど成り立たず, 従って m のインクリメントも起きないということが考えられます. でどうするかというと先生のいわれる「マジックナンバー 32768.0 を使うな」で, これを (普通は) (RAND_MAX + 1.0) で置き換えます. #1 のように (float)RAND_MAX で置き換えてもいいんだけど, 前者だと 0以上 1未満, 後者だと 0以上 1以下の乱数になります.今の場合にはほとんど問題ないはずですが, おそらく前者の方が安全. ちなみに pai じゃなくて pi ね.

その他の回答 (3)

  • php504
  • ベストアンサー率42% (926/2160)
回答No.4

floatはdoubleに型をそろえた方がいいのでは

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

pai_calc関数のmをint型に変えて、 pai=4*m/n; の文を pai=4.0*m/n; に変えてみたら、どうなるでしょうか。 また、今のコードでは毎回同じ結果を得るので、 乱数を使うプログラムとしてはあまりおもしろくないような気がします。 main関数の先頭あたりで、乱数を初期化するための srand関数を実行すると、毎回結果が変わっておもしろいかもしれません。 ちなみに、少数ではなくて小数です。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.1

32768.0を(float)RAND_MAXに置き換えてみては? RAND_MAXはstdlib.hで定義されています。

関連するQ&A

  • 型変換??

    int RANDOM_FUNCTION( int n ) { return (int)( rand() / (float)RAND_MAX * n ); } について Q1.この関数は0からn-1までの乱数を作るそうなのですが,何故ですか? 0<=rand()<=RAND_MAX だから0からnまでの乱数ができるような気がするのですが. Q2.RAND_MAXではなく(float)RAND_MAXとキャストしてある意味は何ですか? Q3.srand((unsigned)time(NULL));と srand((unsigned int)time(NULL));では何か違いますか? Q4.  static int first = 0; if (first == 0){ srand((unsigned)time(NULL)); first = 1; } という処理でsrand((unsigned)time(NULL));は最初の一回だけ呼び出されるようになっているようですが,この部分を srand((unsigned)time(NULL)); というように毎回呼び出すようにするとどうなりますか? 一回呼び出すだけで乱数系列の初期値が呼び出される時に変化しているのですか? Q5.この関数とは関係ない質問ですが,例えば a:int型 b:int型 c:double型 d:float型 のとき d = a / b + c という演算は 1 a:int型,b:int型より(a / b)の結果はint型(小数になった場合は小数点以下切り捨て) 2 (a / b):int型,c:double型,int<doubleより (a / b + c)の結果はdouble型 3 d:float型,『=のあるときは左辺の型に合わせる』よりdはfloat型 というように型変換されているという解釈でいいのでしょうか??

  • C++で乱数を重複しないように発生させる

    C++で乱数を重複しないように発生させるようにプログラムを変更しろと言われたのですが、できません。 教えていただきたいです。 #include<iostream> #include<cstdlib> #include<cstring> #include<ctime> using namespace std; int main() { int i,n; int *p; cout<<"何個記憶しますか?"<<endl; cin>>n; p=new int[n]; if(p==NULL){ cout<<"記憶域の確保に失敗しました。"<<endl; return 1; } srand((unsigned)time(NULL)); rand(); i=0; while(i<n){ p[i]=1+(int)((double)rand()/(RAND_MAX+1.0)*75); if(p[i]==p[i]) cout<<"p["<<i<<"]の値"<<p[i]<<endl; i++; } delete[] p; return 0; }

  • 乱数の度数分布を調べたいC言語

    乱数の度数分布をしらべたいのですがうまくいきません。 grand()は標準正規分布の乱数です。(検索してコピペしたものです。) すいませんが、ご教授お願いします。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define RAND() ((double)rand() / (1.0 + RAND_MAX)) double grand(); main(void){ int j, N, n[6]; double x; N=1000; for (j = 1; j <= N; j++) { x = grand(); if(-1.5< x <= -1.0){n[0] = n[0] + 1;} if(-1.0< x <= -0.5){n[1] = n[1] + 1;} if(-0.5< x <= 0.0){n[2] = n[2] + 1;} if(0.0< x <= 0.5){n[3] = n[3] + 1;} if(0.5< x <= 1.0){n[4] = n[4] + 1;} if(1.0< x <= 1.5){n[5]= n[5] + 1;} } printf(" %d \n %d \n %d \n %d \n %d \n %d \n", n[0], n[1], n[2], n[3], n[4], n[5]); return 0; } double grand() { static double V1, V2, S; static int phase = 0; double X; if(phase == 0) { do { double U1 = RAND(); double U2 = RAND(); V1 = 2 * U1 - 1; V2 = 2 * U2 - 1; S = V1 * V1 + V2 * V2; } while(S >= 1 || S == 0); X = V1 * sqrt(-2 * log(S) / S); } else X = V2 * sqrt(-2 * log(S) / S); phase = 1 - phase; return X; }

  • プログラミングについて

    以下のプログラムをコンパイル、実行しようとするとコアダンプと表示されてしまいます。 おそらく配列がうまくいっていないというのは察したのですが、どううまくいっていないのかがわかりません。 原因を教えていただきたいです。 このプログラムは、Nを入力し、0~100までの乱数をN個表示させるものです。 配列を使っているのは、このプログラムが完成したのち、改良してその乱数同士を計算するプログラムにしたいためで、その途中段階でした。 環境は、Cygwinです。 ―――以下ソースコード――― #include <stdio.h> #include <math.h> #include <stdlib.h> int main(void){ int i,N; double u[N]; int ransu; printf("Define N : \n"); //得たい乱数の数を設定 scanf("%d",&N); for(i = 0; i < N; i++) { ransu = rand() % 101 ; //0~100までの乱数を得る u[i] = (double) ransu; printf("%.0f ", u[i]); } printf(" \n"); return 0; } 教えていただける方、いらっしゃいましたら教えていただきたいです。よろしくお願いします。

  • 0 からa-1 までの整数の乱数をn 個発生させ、発生した整数のヒスト

    0 からa-1 までの整数の乱数をn 個発生させ、発生した整数のヒストグラムをプリントアウトしたいです.また,a とnはコマンドラインから引き渡します 0 からa-1 までの整数を発生する乱数の書き方は (int)((double)rand()/((double)RAND_MAX+1) *a); プログラムをRandHist としたとき RnadHist 10 1000 と入力すれば 0 982 1 1035 2 956 3 1102 ・ ・ 9 971 などと。出力されるようなプログラムを作る問題ですが,a とn は、任意に変えられるように したいです. どなたか教えてください.

  • 配列の要素数に変数を入れたい

    配列に数の入力履歴を入れて最後にその数を出力したいのですが、変数を入れることはできないと勉強した記憶がありまさにその通りコンパイルエラーが出ました。 他に何か方法はありませんでしょうか。 /* 課題1-3 */ #include <time.h> #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void) { int i; int no1; /* 範囲1 */ int no2; /* 範囲2 */ int max; /* 大きい乱数 */ int min; /* 小さい乱数 */ int y; /* 当てさせる数 */ int stage; /* 入力回数 */ int x; /* 読み込んだ値 */ int n; /* 入力制限 */ srand(time(NULL)); no1 = rand(); no2 = rand(); if(no1 > no2){ max = no1; min = no2; } else{ max = no2; min = no1; } y = min + rand() % (max-min); n = ceil(log(max-min)/log(2)); int a[n]; /*←配列の要素数をn個にしたい*/ printf("%d以上%d以下の整数を当ててください。\n", min, max); stage = 0; do{ printf("残り%d回。いくつでしょう:\n", n - stage); scanf("%d", &x); a[stage++] = x; if(y > x) printf("小さいです。\n"); else if(y < x) printf("大きいです。\n"); }while(y != x && stage < n); if(y != x) printf("残念でした。正解は%dです。", y); else printf("正解です。%d回目で正解しました。", stage); puts("\n---入力履歴---"); for(i=0; i<stage; i++) printf("%2d : %4d %+4d\n", i+1, a[i], a[i] - y); return (0); }

  • 離散フーリエ変換について

    double DiscreteFourierTransformClass::DiscreteFourierTransformProcess(int n) { double e=2.7182818; double Pai=3.1415926535; int Tau=10; int N=DataLen/Tau; double Sum=0; for(int k=0;k<N;k++) { Sum+=Tau*Data[k*Tau]*pow(e,i*2*Pai*k*n/N); } return Sum; } Tau*Data[k*Tau]=帯 pow(e,i*2*Pai*k*n/N)=ほしい周波数の乗算 ということで、離散フーリエ展開と同じなのでしょうか? パソコン上で計算するには、離散フーリエ展開で計算して、 FFTというのは、pow(e,i*2*Pai*k*n/N)この回転子が3,4個程度のcos,sinで決まるから その値で計算すれば高速になるよということでしょうか? 離散フーリエ変換 G(n/N)=Σ[k=0::N-1]{τ*f(kτ)e^-i2πkn/N} k:何番目の値か τ:値を読んだ間隔 N:値を読んだ数 n:基本周波数の何倍か G(n/N)->ほしいnの成分を得る

  • nextDoubleが使えない?

    nextDoubleを使って,乱数で生成した値を○○.○や○○○.○といった 小数点第一位までに直したいのですが,乱数がそのまま出力され,上手くできません. いろいろ考えたのですが,原因が分かりませんでした. どこに問題があるのか,何が間違っているのか教えてください. 問題のプログラム //乱数生成 Date date = new Date(); Random rand = new Random(date.getTime()); //値を変換 for(int i=0; i<3; i++){  x[i] = (float)(XRANGE * rand.nextDouble());  y[i] = (float)(YRANGE * rand.nextDouble());  rgb[i] = (float)(rand.nextDouble()); } (補足)  XRANGE,YRANGEは500.0(double型)  配列は全てfloat型  importしているのは,   java.util.Random   java.util.Date   java.io.PrintStream   よろしくお願いします.

    • ベストアンサー
    • Java
  • Cプログラムです

    #include<stdio.h> #include<math.h> int main(void) { double D[512]; short data[16000]; double datafft[512]; double horizon[256]; double dB[256]; double power[256]; double Xr[512],Xi[512]; double w, pai=3.1415926; double er, ei; double r,x,r1,x1,r2,x2 ; int i,k,n,N=500; for(k = 0; k < N; k++) { Xr[k] = 0.0; Xi[k] = 0.0; for(n = 0; n < N; n++) { w = 2 * pai * k * n / N; er = cos(w); ei = sin(-w); r = r1 * r2 - x1 * x2; x = r1 * x2 + r2 * x1; Xr[k] = Xr[k] + er / N; Xi[k] = Xi[k] + ei / N; } } for(i=0;i<512;i++) { datafft[i] = (double)data[i+1000]; power[i] = Xr[i] * Xr[i] + Xi[i] * Xi[i]; } for(i=0;i < 256;i++) { horizon[i] = 16000.0 * ((double)i /512); dB[i] = 10 * log10(power[i]); printf("%f %f \n", horizon[i], dB[i]); } } 正規乱数を発生させたいんですけど、変な値が出てしまいます。 正しくはどうすれば良いか教えてもらえませんか?

  • モンテカルロ法の面積近似

    Mが2の32乗の、線形合同法で乱数を発生し、 モンテカルロ法を使って、 領域a = {(x,y)|x≧1,y≧2,(x-1)^2 + (y-2)^2 ≦1}の面積の近似値を計算するプログラムを作成し、これを利用してn=10000とした場合の上の領域の面積、および円周率πの近似値を求めよ。 (関数を使う) という課題が出たのですが、乱数の出し方?が変であまり近似されません(^_^;) どなたかどこが変か教えてください(>_<) これだと、2と4になってしまうんです(/_;) #include<stdio.h> #include<stdlib.h> #include<math.h> #define N 100 /*領域Rを含む面積T 領域R=求める面積*/ #define Nx 1 #define Ny 2 /*乱数を発生させる関数*/ unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c); int main(){ unsigned long int x0, a, c, M; double x, y, s; int n, count_in, count_out; count_in = 0; count_out = 0; printf("x0: ", x0 ); scanf("%d", &x0); a = 61; c = 49; for(n = 0; n < 10000; n++){ /*乱数を発生*/ x = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Nx + 1; y = (random_g(x0, 4*a*n+1, c) / (double)4294967296)*Ny + 1; if(x >= 1 && y >= 1 && pow(x-1, 2) + pow(y-2, 2) <= 1) count_in++; else count_out++; } s = (double)count_in/(count_in + count_out)*Nx*Ny; printf("s = %f\n", s); printf("pi = %f\n", 2*s); return 0; } unsigned long int random_g(unsigned long int x0, unsigned long int a, unsigned long int c){ int i; x0 = (a*x0 + c); /*printf("%u\n", x0);*/ return x0; }

専門家に質問してみよう