コンピュータ基礎実験 第11回 コンピュータープログラミング (C言語)(8) 1.乱数(復習) 2.配列とその利用 乱数(復習) ランダムに変化する数を生成する関数「乱数」 C言語の乱数:「rand()」関数 #include <stdlib.h> が必要 srand(s): 乱数系列の初期化関数(sはint型整数) srand(s)を実行した時点から、sに応じた乱数の系列が始まる sが同じなら同じ乱数の列が得られる 「srand((unsigned int)time(NULL));」を使うとsをいちいち入力する 手間が省ける(time()関数を使うには「#include <time.h>」が必要) #include <stdlib.h> #include <time.h> Int main(void) { ‥‥ srand((unsigned int)time(NULL)); ‥‥ ‥‥ rn=rand(); ‥‥ } 前回課題 10-7 0から9までの乱数をN個発生させ,それぞれの数字が出た回数およ び確率を出力するプログラムを作成せよ。 とくにN=100と10000 の場合について, 確率のバラツキはどちらが小さいか確認せよ。 ( ex10-7.c) 0から9までの乱数は、「rand()%10」で発生させる 0~9ごとの発生回数はメンバー数10のint型配列に記録する int ev[10]={0,0,0,0,0,0,0,0,0,0}; 0で初期化しておく 配列を使わずに、ev0, ev1, ev2‥‥でもよいが、出た乱数毎にswitch, case文で場合分けすることが必要 回数のカウントアップには、「ev[rn]++;」を実行すればよい i++; ⇔ i+=1; ⇔ i=i+1; ← 全部同じ結果 3 前回課題 10-7 0から9までの乱数をN個発生させ,それぞれの数字が出た回数およ び確率を出力するプログラムを作成せよ。 とくにN=100と10000 の場合について, 確率のバラツキはどちらが小さいか確認せよ。 ( ex10-7.c) #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { int i,n_ev,rn; int ev[10]={0,0,0,0,0,0,0,0,0,0}; srand((unsigned int)time(NULL)); printf("Input number of events: "); scanf("%d",&n_ev); for(i=0; i<n_ev; i++){ rn=rand()%10; ev[rn]++; } for(i=0; i<10; i++){ printf("%dは%d回、確率は%fで す\n",i,ev[i],(float)ev[i]/n_ev); } return 0; } 4 配列とその利用 乱数発生回数のカウントアップに配列を利用し ましたが、それ以外に配列を利用できないでしょ うか? 「確率のバラツキ」をもとめるには、平均と標準偏差 が必要⇒カウントアップに用いた配列を利用して は! 「数の組」⇒ベクトル、行列の計算に利用できない か? ベクトル、行列⇒連立方程式を解くことに利用できな いか? 配列を使った平均、標準偏差計算 0~9の出現回数がev[0]~ev[9]に記録されてい る。これを利用して、出現回数と確率の平均値と バラツキを計算しよう。 平均値: 1 N 1 xi x1 x2 xN N i 1 N 標準偏差(バラツキの指標): 1 N 2 x i N 1 i 1 1 N 2 x i N 1 i 1 1 N 2 2 xi N N 1 i 1 例題 11-1 0から9までの乱数をN個発生させ,それぞれの数字が出た回数の平 均値と標準偏差を計算せよ。 とくにN=100と10000 の場合につい て平均値と標準偏差(バラツキ)を計算せよ。 ( ex11-1.c) #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> int main(void) { int i,n,rn; float m=0,s=0; int ev[10]={0,0,0,0,0,0,0,0,0,0}; srand((unsigned int)time(NULL)); printf("Input number of events: "); scanf("%d",&n); for(i=0; i<n; i++){ rn=rand()%10; ev[rn]++; } for(i=0; i<10; i++){ m+=(float)ev[i]; s+=(float)ev[i]*ev[i]; } m/=10; /* m=m/10; と同じ意味 */ s-=(10*m*m); 1 N 2 xi N 2 s/=(10-1); N 1 i 1 s=sqrt(s); printf(”"平均値=%f 標準偏差 =%f\n",m,s); return 0; } *sqrt()を使うので、「#include <math.h>」 が必要 7 平均値が毎回ぴったり同じなのははぜ? 課題 11-2 0から9までの乱数をN個発生させ,それぞれの数字がでた確率の平 均値と標準偏差(バラツキ)を計算せよ。 とくにN=100と10000 の場合について標準偏差の大きさを比較せよ。 ( ex11-2.c) 例題 11-3 一様な確率分布の乱数を複数個足した数は、正規分布(ガウス分 布)に従うことが知られている。いま、0~9の間に一様に分布す る整数の乱数を10個足し5で割った整数をXとする。XをN個発生さ せ、それぞれの数字が出た回数および確率を出力するプログラムを 作成せよ。 ( ex11-3.c) 結果の確率分布をエクセルでグラフにせよ。 0~9の乱数は「rand()%10」で生成できそう 一個のXを発生させるのに、10回ループする「for文」で、「rand()」 で生成した乱数を足していけばよい 上のループをN回繰り返せばよい 発生回数のカウントアップはex10-7.cのやり方が利用できそう Xの範囲は0~18の整数になる *画面出力をファイルに保存する方法は、 http://www.tuat.ac.jp/~muroo/computer-tips.html を参照 $ ./ex11-3.exe | tee result.dat とすると、result.datに保存される エクセルからは、「開く」から、「すべてのファイル」で読み込める 9 例題 11-3 一様な確率分布の乱数を複数個足した数は、正規分布(ガウス分 布)に従うことが知られている。いま、0~9の間に一様に分布す る整数の乱数を10個足し5で割った整数をXとする。XをN個発生さ せ、それぞれの数字が出た回数および確率を出力するプログラムを 作成せよ。 ( ex11-3.c) 結果の確率分布をエクセルでグラフにせよ。 #include <stdio.h> #include <stdlib.h> #include <time.h> for(i=0; i<n_ev; i++){ rn=0; for(j=0; j<10; j++){ rn+=rand()%10; } rn/=5; ev[rn]++; } int main(void) { int i,j,n_ev,rn; int ev[19]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0}; srand((unsigned int)time(NULL)); printf("Input number of events: "); scanf("%d",&n_ev); for(i=0; i<19; i++){ printf("%d %d\n",i,ev[i]); } return 0; } 10 配列を使ったベクトル、行列の計算 複数の数の組を一括して扱う数学の概念に、 「ベクトル」と「行列」があります 「ベクトル」は添え字が1変数の配列を、「行列」 は添え字が2変数の配列を用いるとC言語で扱う ことができます。 1.2 v 3.7 v[3] {1.2,-3.7,0.23}; 0.23 1 2 3 M 4 5 6 m[3][3] {{1,2,3},{4,5,6},{7,8,9}}; 7 8 9 例題 11-4: 3X3行列の配列による表現と画面出力 1 2 3 行列 M 4 5 6 7 8 9 を添え字が2変数の配列を用いて表現し、画面に出力せよ。 ( ex11-4.c) #include <stdio.h> i int main(void) 0 1 2 { float m[3][3]={{1,2,3},{4,5,6},{7,8,9}}; int i,j; 0 12 j for(i=0; i<3; i++){ for(j=0; j<3; j++){ printf("%f ",m[i][j]); } printf("\n"); } return 0; } i行j列の行列を配列m[i][j]で表す 行iのループの中に、列jのループ(2重) 「for」ループを2重につかって、 内側のループ(j)で列を 外側のループ(i)で行を 繰り返して画面表示 1列目 2列目 3列目 (j=0) (j=1) (j=2) 1行目 1 2 3 (i=0) 2行目 4 5 6 (i=1) 3行目 7 8 9 (i=2) 12 例題 11-5 3次元ベクトルを2個入力し、2個のベクトルの、「和」、「差」、 「内積」を計算して表示せよ。( ex11-5.c) #include <stdio.h> void inputvec(float a[3]); int main(void) { float a[3],b[3]; float sum[3],diff[3],inner_p=0; int i; inputvec(a); inputvec(b); for(i=0; i<3; i++){ /* 成分のためのループ*/ sum[i]=a[i]+b[i]; /* 和の計算 */ diff[i]=a[i]-b[i]; /* 差の計算 */ inner_p+=a[i]*b[i]; /* 内積の計算 */ } printf("和\t\t差\n"); タブ(一定の文字送り) for(i=0; i<3; i++){ printf("%f\t%f\n",sum[i],diff[i]); } printf("内積: %f\n",inner_p); return 0; } void inputvec(float a[3]) { float w; int i; printf("ベクトルの成分を入力してください: "); for(i=0; i<3; i++){ scanf("%f",&w); a[i]=w; } } 13 例題 11-6 3X3正方行列を2個入力し、2個の行列の和を計算して表示せよ。 また積の1,1成分を計算して表示せよ。( ex11-6.c) 2次元配列なので、「for文」の2重ループで、行(i) のループの中に列(j)のループを入れて成分ごと に和を計算すればよい 積の1,1成分は行列Aの1行目と行列Bの一列目 について成分の積の和をとる a11 a21 a 31 a12 a22 a32 a13 b11 b12 a23 b21 b22 a33 b31 b32 b13 b23 b33 ab11 a11b11 a12b21 a13b31 14 例題 11-6 3X3正方行列を2個入力し、2個の行列の和を計算して表示せよ。 また積の1,1成分を計算して表示せよ。( ex11-6.c) #include <stdio.h> void inputmatrix(float a[3][3]); int main(void) { float a[3][3],b[3][3],sum[3][3]; float product[3][3]={{0,0,0},{0,0,0},{0,0,0}}; int i,j,k; inputmatrix(a); inputmatrix(b); for(i=0; i<3; i++){ for(j=0; j<3; j++){ sum[i][j]=a[i][j]+b[i][j]; } } printf("和\n"); for(i=0; i<3; i++){ for(j=0; j<3; j++){ printf("%f\t",sum[i][j]); } printf("\n"); } for(k=0; k<3; k++){ product[0][0]+=a[0][k]*b[k][0]; } printf("積の1,1成分: %f\n",product[0][0]); return 0; } void inputmatrix(float a[3][3]) { int i,j; float w; for(i=0; i<3; i++){ printf("行列の%d行めの成分を入力してくださ い: ",i+1); for(j=0; j<3; j++){ scanf("%f",&w); a[i][j]=w; } } } 15 課題 11-7 3X3正方行列を2個入力し、2個の行列の積を計算するプログラ ムを完成させよ。( ex11-7.c) ex11-6.cでは1,1成分について計算している i, j成分を計算するにはどこを変更すればよ いか for(k=0; k<3; k++){ product[0][0]+=a[0][k]*b[k][0]; } i j 「for文」でiとjについてループを回せばよい (ex11-6.cのinputmatrix()関数を参照) 16 例題 11-8 (発展:任意の次元のベクトル) 「DIM」次元ベクトルを2個入力し、2個のベクトルの、「和」、 「差」、内積を計算して表示せよ。「DIM」の値をいろいろ変えて コンパイルして結果を比較せよ。( ex11-8.c) #include <stdio.h> #define DIM 3 void inputvec(float a[DIM]); int main(void) { float a[DIM],b[DIM]; float sum[DIM],diff[DIM],inner/_p=0; int i; inputvec(a); inputvec(b); for(i=0; i<DIM; i++){ /* 成分のためのループ*/ sum[i]=a[i]+b[i]; /* 和の計算 */ diff[i]=a[i]-b[i]; /* 差の計算 */ inner_p+=a[i]*b[i]; /* 内積の計算 */ } printf("和\t\t差\n"); for(i=0; i<DIM; i++){ printf("%f\t%f\n",sum[i],diff[i]); } printf("内積: %f\n",inner_p); return 0; } void inputvec(float a[DIM]) { float w; int i; printf("ベクトルの成分を入力してください: "); for(i=0; i<DIM; i++){ scanf("%f",&w); a[i]=w; } } 「#define DIM 3」とすると、以下の「DIM」の 部分が全て「3」に置き換わる。 「#define DIM 3」を「#define DIM 4」とすれ ば4次元ベクトル用のプログラムになる。 17 配列を使った連立方程式の解法 連立(代数)方程式は行列を用いて表すことが できます⇒線型代数 係数部分を表す「係数行列」の逆行列が求まれ ば、逆行列の掛け算によって、解は簡単に求ま ります 行列、ベクトルを配列で表すことにより、2変数 (x,y)連立方程式を解くプログラムを作ろう 2変数連立方程式と行列 2変数連立方程式の行列による表現 ax by e a b x e cx dy f c d y f 係数行列 A もし逆行列A-1が求まれば a b 1 0 , A1 c d 0 1 a b x e a b x e c d y f c d y f 1 0 x e 0 1 y f 2X2行列の逆行列 2X2行列の逆行列 a b 1 d b 1 のとき A A ad bc c a c d ただし ad bc 0 (ad bc 0の時、逆行列は存在し ない ) 例題 11-9 2X2行列を入力し、逆行列を表示するプログラムを作成せよ。 ( ex11-9.c) #include <stdio.h> #define DIM 2 printf("逆行列:\n"); for(i=0; i<DIM; i++){ for(j=0; j<DIM; j++){ printf("%f\t",inv_a[i][j]); } printf("\n"); } void inputmat(float a[DIM][DIM]); int main(void) { float a[DIM][DIM],inv_a[DIM][DIM],determinant; int i,j; } return 0; inputmat(a); } determinant=a[0][0]*a[1][1]-a[0][1]*a[1][0]; if(determinant==0){ printf("逆行列は存在しない\n"); } else{ inv_a[0][0]=a[1][1]/determinant; inv_a[1][1]=a[0][0]/determinant; inv_a[0][1]=-a[0][1]/determinant; inv_a[1][0]=-a[1][0]/determinant; void inputmat(float a[DIM][DIM]) { float w; int i,j; printf("行列の成分を入力してください:\n"); for(i=0; i<DIM; i++){ for(j=0; j<DIM; j++){ scanf("%f",&w); a[i][j]=w; } } } 21 課題 11-10 2X2の係数行列と、2成分定数ベクトルを入力し、連立方程式を解 くプログラムを作成せよ。解が存在しない(不定、不能)場合には 「解なし」と出力すること。( ex11-9.c) 係数行列の逆行列を定数ベクトルに掛けて 得たベクトルの成分が、解x,yになる 逆行列が存在しないとき⇒「不定」、「不能」 の解なしに対応 22 特別課題 11-11 N連の連立方程式を解くプログラムを作成せよ。解が存在しない (不定、不能)場合には「解なし」と出力すること。( ex1111.c) N連の連立方程式を解くためにはNXN正方 行列(係数行列)の逆行列が求まればよい NXN正方行列の逆行列を求めるには、ガウス・ ジョルダン法(Gauss-Jordan elimination)がある ⇒中学でならう消去法と同じもの ガウス・ジョルダン法の簡略化バージョンとして、 ガウス消去法(Gaussian elimination)がある WEBでアルゴリズムを調べてみよ(提出に はおよばない) 23 実習結果のレポート • 3つのソースファイル「ex11-2.c」、「ex11-7.c」、 「ex11-10.c」を添付ファイルにしてメールを送っ てください。 • 宛先: [email protected] • 件名:コンピューター基礎実験11 • 本文:感想および一言 24
© Copyright 2024 ExpyDoc