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

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

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

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

Q&A

解決済

3回答

4170閲覧

正規乱数を生成し、その平均値と分散を求めるプログラムの出力がうまくいきません。

jackie687456

総合スコア17

C

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

0グッド

0クリップ

投稿2017/05/27 16:52

編集2017/05/28 06:52

###前提・実現したいこと
乱数を二つ生成し、Box-Muller法を用いて、平均1、分散4に従う正規乱数を生成するプログラムを作成し、乱数をn個生成し、標本平均値と標本分散をいくつかのnごとに求める。という課題で、作って実行してみると、エラーは出ないのですが何も出力されません。原因を教えていただければ助かります。
また、#defineと#undefを繰り返してnの値を変えているのですが、繰り返し文のようなものは使えないのでしょうか?ご回答、よろしくお願いいたします。

###発生している問題・エラーメッセージ

エラーは出ないのですが、何も出力されません。

###該当のソースコード

#include<stdio.h> #include<math.h> #include<stdlib.h> #define mu 1.0 #define sigma 2.0 #define PI 3.1415926535897932384626433832795 #define n 500 void Random(double I, double *R){ int a, k; long m; a = 69621; m = pow(2, 32); for (k = 0; k<n; k++){ I = a*I - floor(a*I / m)*m; R[k] = I / (m - 1); } } void Ri(void){ int i, k; double total, v, aver, disp; double u1[n], u2[n], x[n], X[n]; Random(1.0, u1); Random(2.0, u2); for (i = 0; i<n; i++){ x[i] = sqrt(-2 * log(u1[i]))*cos(2 * PI*u2[i]); X[i] = sigma * x[i] + mu; } total = 0; for (i = 0; i < n; i++){ total += X[i]; aver = total / n; } v = 0; for (i = 0; i<n; i++){ v += (aver - X[i])*(aver - X[i]); disp = v / n; } printf("%d %f %f\n", n, aver, disp); } int main(void){ Ri; #undef n #define n 1000 Ri; #undef n #define n 1500 Ri; #undef n #define n 2000 Ri; #undef n #define n 2500 Ri; #undef n #define n 3000 Ri; #undef n #define n 3500 Ri; #undef n #define n 4000 Ri; #undef n #define n 4500 Ri; #undef n #define n 5000 Ri; return 0; }

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

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

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

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

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

guest

回答3

0

ベストアンサー

どうやら関数呼び出し演算子「()」が抜けているようです。

[追記]
「nを変える方法」については、nはdouble配列の要素数としても使っているので、単純にnを関数Riの引数で与えるようにしてもうまくいかないかと思います。配列はある程度の大きさで一定にして(少なくとも5000以上でないとまずいですね)、それ以外のnをRiの引数にすることができそうです。関数Randomも内部でnを使っているので、Randomに引数を追加して置き換えてやる必要があるでしょう。あとは繰り返し文でRiの引数を変えてしまえば、意図通りになるかと思います。
配列の長さを可変にするため、動的にメモリ領域確保をする手もあると思いますが、こういった実験的なプログラムではそこまでせずともよいのではないでしょうか。

[さらに追記]
質問者さんの少し前のご質問を拝見しました。あそこまで出来上がっていたのなら、あとは配列の要素数の部分だけ定数にしてしまえばよさそうです。

C

1#define N_MAX 5000 2 3/* 中略 */ 4 5double u1[N_MAX], u2[N_MAX], x[N_MAX], X[N_MAX];

こんな感じでしょうか?

[もう一つ追記]
もしnを数万、数十万まで増やして試したい場合、今度はスタック領域が食いつぶされてクラッシュするかもしれません。そうなるようでしたら動的ヒープ確保に書き換えた方がいいでしょう。先のトピックのRefshizさんが挙げられたサイトなどがご参考になるかと思います。

投稿2017/05/27 20:02

編集2017/05/27 21:30
Bongo

総合スコア10807

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

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

jackie687456

2017/05/28 06:21

ご回答ありがとうございました。関数呼び出し演算子()が抜けていたことになぜ気が付かなかったのか、お恥ずかしい限りです。追記の方でも大変詳しくありがとうございます。一回目に質問させていただいたときのプログラムの方を次のように変えてみたのですが、値が全て-1.#IND00と出てきてしまいます。 調べてみると値が無限大になってしまっているのかなと考えているのですが…。該当箇所がわからず解決できずにいます。どうか引き続きご助力願えませんでしょうか? ''' #include<stdio.h> #include<math.h> #include<stdlib.h> #define mu 1.0 #define sigma 2.0 #define PI 3.1415926535897932384626433832795 #define N_MAX 5000 void Random(double I, int n, double *R){ int a, k; long m; a = 69621; m = pow(2, 32); for (k = 0; k<n; k++){ I = a*I - floor(a*I / m)*m; R[k] = I / (m - 1); } } int main(void){ int i, k, n; double total, v, aver, disp; double u1[N_MAX], u2[N_MAX], x[N_MAX], X[N_MAX]; printf(" n average dispersion\n"); for (k = 1; k <= 10; k++){ n = k * 500; Random(1.0, n, u1); Random(2.0, n, u2); for (i = 0; i<n; i++){ x[i] = sqrt(-2 * log(u1[i]))*cos(2 * PI*u2[i]); X[i] = sigma * x[i] + mu; } total = 0; for (i = 0; i < n; i++){ total += X[i]; aver = total / n; } v = 0; for (i = 1; i<n; i++){ v += (aver - X[i])*(aver - X[i]); disp = v / n; } printf("%5d %f %f\n", n, aver, disp); } return 0; } '''
jackie687456

2017/05/28 06:23

追記 こういう場合には、新たに質問を立て直させていただいた方がいいんでしょうか?
Bongo

2017/05/28 12:12 編集

怪しいところを思いつきました。 ご質問者様の環境で、sizeof(long)とsizeof(double)はいくつになるでしょうか?もし前者の方が小さい場合、関数Randomの中のm = pow(2, 32);で不正な値が格納→Randomの結果がマイナスに→log(u1[i])が定義域のエラー...という状況になるかもしれません。 とりあえず、long m;をdouble m;にしてみて、何か状況は変化するでしょうか? [追記] もう一つの確認方法として、printf("LONG_MAX:%ld\n", LONG_MAX);とするといくつが表示されるでしょうか。私の場合だと「LONG_MAX:9223372036854775807」でしたが、もし「LONG_MAX:2147483647」などとなるようでしたら、longに2の32乗は格納できないということになります。
jackie687456

2017/05/28 12:46

追加でご回答ありがとうございました。回答者様のご指摘通り、longの方が小さく、正しく値が出ていなかったようで、double m;に変えることで解決いたしました。適切で丁寧なご回答、本当にありがとうございました!
guest

0

これでうまくいきます。

C

1#include<stdio.h> 2#include<math.h> 3#include<stdlib.h> 4 5#define mu 1.0 6#define sigma 2.0 7#define PI 3.1415926535897932384626433832795 8 9void Random(double I, double *R, int n) { 10 int a, k; 11 long m; 12 13 a = 69621; 14 m = pow(2, 32); 15 16 for (k = 0; k<n; k++){ 17 I = a*I - floor(a*I / m)*m; 18 R[k] = I / (m - 1); 19 } 20} 21 22void Ri(int n){ 23 int i, k; 24 double total, v, aver, disp; 25 26 double *u1 = (double*)malloc(n * sizeof(double)); 27 double *u2 = (double*)malloc(n * sizeof(double)); 28 double *x = (double*)malloc(n * sizeof(double)); 29 double *X = (double*)malloc(n * sizeof(double)); 30 31 Random(1.0, u1, n); 32 Random(2.0, u2, n); 33 34 for (i = 0; i<n; i++){ 35 x[i] = sqrt(-2 * log(u1[i]))*cos(2 * PI*u2[i]); 36 X[i] = sigma * x[i] + mu; 37 } 38 39 total = 0; 40 41 for (i = 0; i < n; i++){ 42 total += X[i]; 43 aver = total / n; 44 } 45 46 v = 0; 47 48 for (i = 0; i<n; i++){ 49 v += (aver - X[i])*(aver - X[i]); 50 disp = v / n; 51 } 52 53 free(u1); 54 free(u2); 55 free(x); 56 free(X); 57 58 printf("%d %f %f\n", n, aver, disp); 59 60} 61 62int main(void){ 63 64 Ri(500); 65 66 Ri(1000); 67 68 Ri(1500); 69 70 Ri(2000); 71 72 Ri(2500); 73 74 Ri(3000); 75 76 Ri(3500); 77 78 Ri(4000); 79 80 Ri(4500); 81 82 Ri(5000); 83 84 return 0; 85}

投稿2017/05/27 23:40

naomi3

総合スコア1105

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

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

jackie687456

2017/05/28 04:30

ご回答ありがとうございます。mallocのことをそもそもわかっておりません。今度調べて勉強してみます。
naomi3

2017/05/28 04:39

mallocは動的にメモリを確保する関数で、よく使います。
guest

0

#define n 1000は、ソースコードをエディタで#undef nまでの範囲で、nという語を全部1000に置換してからコンパイルするのと同じです。
つまり、

C

1#define n 1000 2 Ri; 3#undef n

は、#define#undefの範囲内にnという語が現れないので、単に、

C

1 Ri;

と書いたのと全く同じです。

間違っているのは、
1. #defineの意味を理解していない
2. 関数呼び出しに括弧が無い
の2点です。

gccの場合、配列宣言の添え字に変数が使えるので、nを普通の変数にして、

C

1 ~~~ 2 3void Random(int n, double I, double *R){ 4 ~~~ 5} 6 7void Ri(int n){ 8 ~~~ 9} 10 11int main(void){ 12 int n; 13 for(n=500; n<=5000; n+=500){ 14 Ri(n); 15 } 16 return 0; 17}

gccでなくてもC99規格のコンパイラだと大丈夫です。
それ以外のコンパイラの場合は、配列宣言のところをサイズ5000で宣言する必要があります。

投稿2017/05/27 23:09

otn

総合スコア84423

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問