Download presentation
Presentation is loading. Please wait.
1
コンピュータープログラミング (C言語)(8) 1.乱数(復習) 2.配列とその利用
コンピュータ基礎実験 第11回 コンピュータープログラミング (C言語)(8) 1.乱数(復習) 2.配列とその利用
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(); }
3
前回課題 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; ← 全部同じ結果
4
前回課題 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;
5
配列とその利用 乱数発生回数のカウントアップに配列を利用しましたが、それ以外に配列を利用できないでしょうか?
「確率のバラツキ」をもとめるには、平均と標準偏差が必要⇒カウントアップに用いた配列を利用しては! 「数の組」⇒ベクトル、行列の計算に利用できないか? ベクトル、行列⇒連立方程式を解くことに利用できないか?
6
配列を使った平均、標準偏差計算 0~9の出現回数がev[0]~ev[9]に記録されている。これを利用して、出現回数と確率の平均値とバラツキを計算しよう。 平均値: 標準偏差(バラツキの指標):
7
例題 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); s/=(10-1); s=sqrt(s); printf(”"平均値=%f 標準偏差=%f\n",m,s); return 0; *sqrt()を使うので、「#include <math.h>」 が必要 平均値が毎回ぴったり同じなのははぜ?
8
課題 11-2 0から9までの乱数をN個発生させ,それぞれの数字がでた確率の平均値と標準偏差(バラツキ)を計算せよ。 とくにN=100と10000 の場合について標準偏差の大きさを比較せよ。 ( ex11-2.c)
9
0~9の乱数は「rand()%10」で生成できそう
例題 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の整数になる *画面出力をファイルに保存する方法は、 を参照 $ ./ex11-3.exe | tee result.dat とすると、result.datに保存される エクセルからは、「開く」から、「すべてのファイル」で読み込める
10
結果の確率分布をエクセルでグラフにせよ。
例題 11-3 一様な確率分布の乱数を複数個足した数は、正規分布(ガウス分布)に従うことが知られている。いま、0~9の間に一様に分布する整数の乱数を10個足し5で割った整数をXとする。XをN個発生させ、それぞれの数字が出た回数および確率を出力するプログラムを作成せよ。 ( ex11-3.c) 結果の確率分布をエクセルでグラフにせよ。 #include <stdio.h> #include <stdlib.h> #include <time.h> 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<n_ev; i++){ rn=0; for(j=0; j<10; j++){ rn+=rand()%10; } rn/=5; ev[rn]++; for(i=0; i<19; i++){ printf("%d %d\n",i,ev[i]); return 0;
11
配列を使ったベクトル、行列の計算 複数の数の組を一括して扱う数学の概念に、「ベクトル」と「行列」があります
「ベクトル」は添え字が1変数の配列を、「行列」は添え字が2変数の配列を用いるとC言語で扱うことができます。
12
例題 11-4: 3X3行列の配列による表現と画面出力 行列
を添え字が2変数の配列を用いて表現し、画面に出力せよ。 ( ex11-4.c) #include <stdio.h> int main(void) { float m[3][3]={{1,2,3},{4,5,6},{7,8,9}}; int i,j; for(i=0; i<3; i++){ for(j=0; j<3; j++){ printf("%f ",m[i][j]); } printf("\n"); return 0; i i行j列の行列を配列m[i][j]で表す 行iのループの中に、列jのループ(2重) 「for」ループを2重につかって、 内側のループ(j)で列を 外側のループ(i)で行を 繰り返して画面表示 2 1 1 2 j 1列目 2列目 3列目 (j=0) (j=1) (j=2) 1行目 (i=0) 2行目 (i=1) 3行目 (i=2)
13
3次元ベクトルを2個入力し、2個のベクトルの、「和」、「差」、「内積」を計算して表示せよ。( ex11-5.c)
例題 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; タブ(一定の文字送り)
14
2次元配列なので、「for文」の2重ループで、行(i)のループの中に列(j)のループを入れて成分ごとに和を計算すればよい
例題 11-6 3X3正方行列を2個入力し、2個の行列の和を計算して表示せよ。また積の1,1成分を計算して表示せよ。( ex11-6.c) 2次元配列なので、「for文」の2重ループで、行(i)のループの中に列(j)のループを入れて成分ごとに和を計算すればよい 積の1,1成分は行列Aの1行目と行列Bの一列目について成分の積の和をとる
15
3X3正方行列を2個入力し、2個の行列の和を計算して表示せよ。また積の1,1成分を計算して表示せよ。( ex11-6.c)
例題 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"); 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;
16
i, j成分を計算するにはどこを変更すればよいか
課題 11-7 3X3正方行列を2個入力し、2個の行列の積を計算するプログラムを完成させよ。( ex11-7.c) ex11-6.cでは1,1成分について計算している i, j成分を計算するにはどこを変更すればよいか 「for文」でiとjについてループを回せばよい(ex11-6.cのinputmatrix()関数を参照) for(k=0; k<3; k++){ product[0][0]+=a[0][k]*b[k][0]; } i j
17
例題 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次元ベクトル用のプログラムになる。
18
配列を使った連立方程式の解法 連立(代数)方程式は行列を用いて表すことができます⇒線型代数
係数部分を表す「係数行列」の逆行列が求まれば、逆行列の掛け算によって、解は簡単に求まります 行列、ベクトルを配列で表すことにより、2変数(x,y)連立方程式を解くプログラムを作ろう
19
2変数連立方程式と行列 2変数連立方程式の行列による表現 もし逆行列A-1が求まれば
20
2X2行列の逆行列 2X2行列の逆行列
21
2X2行列を入力し、逆行列を表示するプログラムを作成せよ。 ( ex11-9.c)
例題 11-9 2X2行列を入力し、逆行列を表示するプログラムを作成せよ。 ( ex11-9.c) #include <stdio.h> #define DIM 2 void inputmat(float a[DIM][DIM]); int main(void) { float a[DIM][DIM],inv_a[DIM][DIM],determinant; int i,j; 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; printf("逆行列:\n"); for(i=0; i<DIM; i++){ for(j=0; j<DIM; j++){ printf("%f\t",inv_a[i][j]); } printf("\n"); return 0; void inputmat(float a[DIM][DIM]) { float w; int i,j; printf("行列の成分を入力してください:\n"); scanf("%f",&w); a[i][j]=w;
22
係数行列の逆行列を定数ベクトルに掛けて得たベクトルの成分が、解x,yになる 逆行列が存在しないとき⇒「不定」、「不能」の解なしに対応
課題 11-10 2X2の係数行列と、2成分定数ベクトルを入力し、連立方程式を解くプログラムを作成せよ。解が存在しない(不定、不能)場合には「解なし」と出力すること。( ex11-9.c) 係数行列の逆行列を定数ベクトルに掛けて得たベクトルの成分が、解x,yになる 逆行列が存在しないとき⇒「不定」、「不能」の解なしに対応
23
N連の連立方程式を解くためにはNXN正方行列(係数行列)の逆行列が求まればよい
特別課題 11-11 N連の連立方程式を解くプログラムを作成せよ。解が存在しない(不定、不能)場合には「解なし」と出力すること。( ex11-11.c) N連の連立方程式を解くためにはNXN正方行列(係数行列)の逆行列が求まればよい NXN正方行列の逆行列を求めるには、ガウス・ジョルダン法(Gauss-Jordan elimination)がある ⇒中学でならう消去法と同じもの ガウス・ジョルダン法の簡略化バージョンとして、ガウス消去法(Gaussian elimination)がある WEBでアルゴリズムを調べてみよ(提出にはおよばない)
24
実習結果のレポート 3つのソースファイル「ex11-2.c」、「ex11-7.c」、「ex11-10.c」を添付ファイルにしてメールを送ってください。 宛先: 件名:コンピューター基礎実験11 本文:感想および一言
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.