長文失礼します

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
aegisl

長文失礼します

#1

投稿記事 by aegisl » 14年前

長文失礼します

コード:

#include<stdio.h>
#define N 10000 //生成する一様乱数の個数
#define M 10    //区間分けの個数
#define P(z) z
void frequency(double *x,int *f);//観測度を求める
void expected_frequency(int *e); //期待度数を求める
double x2_test(int *e,int *f); //カイ2乗を求める

int main(void){
    int i;
    int f[M],e[M];     //f:観測度数 e:期待度数
    double a=1229,c=351750,s=300,m=1664501,x2,b;// x2:カイ2乗の値 b:分散
    double r[N],x[N],sum=0.0,sum2=0.0;  //x:一様乱数 r:数列 
    for(i=0;i<M;i++){     //配列の初期化
f[i]=0;
    }
    //一様乱数の生成
    r[0]=s;
    x[0]=r[0]/m;

    for(i=1;i<N;i++){
r[i]=(int)(a*r[i-1]+c)%(int)m;
x[i]=r[i]/m;
    }
    //平均と分散の計算
    for(i=0;i<N;i++){
sum+=x[i];
 printf("x[%d]=%f\n",i,x[i]);//乱数の表示
sum2+=x[i]*x[i];
    }
    b=sum2/N-(sum/N*sum/N);
    printf("平均=%f 分散=%f\n",sum/N,b);
    
    frequency(x,f);   //観測度数の呼び出し
    
    expected_frequency(e);   //期待度数の呼び出し
    
    printf("カイ2乗=%f\n",x2_test(e,f));
       for(i=0;i<M;i++){
    printf("%d\n",f[i]);//区間ごとの個数の表示
    }   
    return 0;
}

void frequency(double *x,int *f){  //配列はポインタでしか渡せないのでポインタを使う?
    int i,k=0,z=0;
    double j=0;

    while(j<1.0){
for(i=0;i<N;i++){
    if(x[i]>=j && x[i]<j+1.0/M){  //範囲内の数ならばkをインクリメントし
k++;                      //観測度数を求める
    }
}
f[z]=k;                            //求めた観測度数を配列に入れる
k=0;
z++;            //区間をカウントしている
j=j+1.0/M;
    }
}

void expected_frequency(int *e){
    int i=0,j=0,sum=0;

    for(i=0;i<M;i++){
e[i]=N*(P(j+1.0/M)-P(j));  //区間[a,b],確率分布関数がP(x)のときの,
        j+=1.0/M;              //期待度数の求め方,N*{P(b)-P(a)}を計算する
sum+=e[i];
    }
}

double x2_test(int *e,int *f){
    int i;
    double x2;
    for(i=0;i<M;i++){
x2+=((double)f[i]-(double)e[i])*((double)f[i]-(double)e[i])/(double)e[i];  //カイ2乗を計算
    }

    return x2;          //カイ2乗の値を返す
}

合同式法により、区間0≦x<1の一様分布に従う疑似乱数を生成し、1次元適合度検定のためカイ2乗統計量を計算するプログラム(計算式は下に)です。
これにコメント文等でこのプログラムの説明をせよと言われたのですが分からないところがあります。(ある程度は自分で書きました)
1つは最初の#define P(z) z の部分はどう使われているのか
2つはr=(int)(a*r[i-1]+c)%(int)m;  の(int)はなぜ必要なのか
3つ目は関数で使われている変数jとsumがどう使われているかです。

「計算式」
一様乱数の求め方の部分は(int)の必要性以外は理解できたので省略します。
カイ2乗の求め方は、
カイ2乗=Σ_k=1 ^M (f_k-e_k)^2/e_k  です
(わかりにくいですがΣの下がk=1,上がM,_は下付きの文字です)
f_kは観測度数、e_kは期待度数です。
生成した乱数を10個の区間に分けて、0~0.1の区間の乱数の個数、0.1~0.2の区間の乱数の個数と計算して、
それぞれの区間に何個乱数ができたのかが観測度数、
期待度数は
連続的確率密度関数がp(x),p(x)の確率分布関数がP(x)とする。このとき、区間[a,b]の期待度数e_a,b はNを総標本数とすると
e_a,b=N×{P(b)-P(a)}
と求められます。
わかりにくいと思うのでこのサイトを見てください→http://ja.wikipedia.org/wiki/%E3%82%AB% ... C%E5%AE%9A
長文失礼しました
その他これ違うというところがあったら教えてくださると助かります。

box
記事: 2002
登録日時: 15年前

Re: 長文失礼します

#2

投稿記事 by box » 14年前

本題に入る前に、そのインデント、何とかならないものでしょうか。せめて、これくらいにはできないものでしょうか。

コード:

#include<stdio.h>

#define N 10000 //生成する一様乱数の個数
#define M 10    //区間分けの個数
#define P(z) z

void frequency(double *x,int *f);//観測度を求める
void expected_frequency(int *e); //期待度数を求める
double x2_test(int *e,int *f); //カイ2乗を求める

int main(void){
    int i;
    int f[M],e[M];     //f:観測度数 e:期待度数
    double a=1229,c=351750,s=300,m=1664501,x2,b;// x2:カイ2乗の値 b:分散
    double r[N],x[N],sum=0.0,sum2=0.0;  //x:一様乱数 r:数列
    for(i=0;i<M;i++){     //配列の初期化
        f[i]=0;
    }
    //一様乱数の生成
    r[0]=s;
    x[0]=r[0]/m;

    for(i=1;i<N;i++){
        r[i]=(int)(a*r[i-1]+c)%(int)m;
        x[i]=r[i]/m;
    }
    //平均と分散の計算
    for(i=0;i<N;i++){
        sum+=x[i];
        printf("x[%d]=%f\n",i,x[i]);//乱数の表示
        sum2+=x[i]*x[i];
    }
    b=sum2/N-(sum/N*sum/N);
    printf("平均=%f 分散=%f\n",sum/N,b);

    frequency(x,f);   //観測度数の呼び出し

    expected_frequency(e);   //期待度数の呼び出し

    printf("カイ2乗=%f\n",x2_test(e,f));
    for(i=0;i<M;i++){
        printf("%d\n",f[i]);//区間ごとの個数の表示
    }
    return 0;
}

void frequency(double *x,int *f){  //配列はポインタでしか渡せないのでポインタを使う?
    int i,k=0,z=0;
    double j=0;

    while(j<1.0){
        for(i=0;i<N;i++){
            if(x[i]>=j && x[i]<j+1.0/M){  //範囲内の数ならばkをインクリメントし
                k++;                      //観測度数を求める
            }
        }
        f[z]=k;                            //求めた観測度数を配列に入れる
        k=0;
        z++;            //区間をカウントしている
        j=j+1.0/M;
    }
}

void expected_frequency(int *e){
    int i=0,j=0,sum=0;

    for(i=0;i<M;i++){
        e[i]=N*(P(j+1.0/M)-P(j));  //区間[a,b],確率分布関数がP(x)のときの,
        j+=1.0/M;              //期待度数の求め方,N*{P(b)-P(a)}を計算する
        sum+=e[i];
    }
}

double x2_test(int *e,int *f){
    int i;
    double x2;
    for(i=0;i<M;i++){
        x2+=((double)f[i]-(double)e[i])*((double)f[i]-(double)e[i])/(double)e[i];   //カイ2乗を計算
    }

    return x2;          //カイ2乗の値を返す
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

aegisl

Re: 長文失礼します

#3

投稿記事 by aegisl » 14年前

見にくくてすいません
ちょっと詰めたのですが、それがかえって見にくかったですね。

box
記事: 2002
登録日時: 15年前

Re: 長文失礼します

#4

投稿記事 by box » 14年前

aegisl さんが書きました: 1つは最初の#define P(z) z の部分はどう使われているのか
2つはr=(int)(a*r[i-1]+c)%(int)m;  の(int)はなぜ必要なのか
3つ目は関数で使われている変数jとsumがどう使われているかです。

1)P(なんとか) という記述があったら、単純に
なんとか
に置き換えているだけです。

2)% 演算子は int 型を対象としているからです。

3)expected_frequency関数のことをおっしゃっているのでしたら、
j も sum も関数内部のローカル変数であり、かつ、同関数の戻り値となっていませんので、
最終的な結果は捨てられています(他に使っている人がいない、という意味)。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

aegisl

Re: 長文失礼します

#5

投稿記事 by aegisl » 14年前

解答ありがとうございました。
たすかりました

閉鎖

“C言語何でも質問掲示板” へ戻る