C言語で簡単なプログラムを作りながら、その基本的な事柄を学んでいこう。
今回のテーマは、「関数(その2)」である。
先に「英語の点数と数学の点数の合計点を平均点を求める」プログラムを作成したが、
このプログラムに分散と標準偏差を求めるように関数を追加してみよう。
英語の点数と数学の点数の合計点と平均点を求め、さらに、分散と標準偏差も求める
要素数がnであるint型の配列vの要素の分散と標準偏差を返す関数を作ってみよう。
/* 英語の点数と数学の点数の合計点と平均点を求める*/
/*さらに、英語と数学の分散と標準偏差も求める*/
#include <stdio.h>
#include <math.h>
#define NUMBER 5 //学生の人数
/*要素数nの配列vの合計点を返す*/
int sum_of(const int v[],int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
sum += v[i];
return sum;
}
/*要素数nの配列vの平均点を返す*/
double ave_of(const int v[], int n)
{
int sum = 0;
sum = sum_of(v,n);
double average = (double)sum / n;
return average;
}
/*分散を求める*/
double var_of(const int v[], int n) {
double ave = ave_of(v,n);
double sum;
sum = 0;
for (int i = 0; i < n; i++) {
double y = (v[i] - ave) * (v[i] - ave);
sum = sum + y;
}
double var = sum / n;
return var;
}
/*標準偏差を求める*/
double sd_of(const int v[], int n) {
double var = var_of(v, n);
double sd = sqrt(var);
return sd;
}
int main(void)
{
int i;
int eng[NUMBER];
int mat[NUMBER];
double ave_e,ave_m;
int sum_e,sum_m;
double var_e,var_m;
double sd_e,sd_m;
printf("%d人の点数を入力してください\n",NUMBER);
for ( i = 0; i < NUMBER; i++)
{
printf("[%d] 英語:",i+1); scanf("%d",&eng[i]);
printf(" 数学:"); scanf("%d",&mat[i]);
}
ave_e = ave_of(eng,NUMBER);
ave_m = ave_of(mat,NUMBER);
sum_e = sum_of(eng,NUMBER);
sum_m = sum_of(mat,NUMBER);
var_e = var_of(eng,NUMBER);
var_m = var_of(mat,NUMBER);
sd_e = sd_of(eng,NUMBER);
sd_m = sd_of(mat,NUMBER);
printf("英語の平均点= %.2f\n",ave_e);
printf("数学の平均点= %.2f\n",ave_m);
printf("英語の合計点= %d\n",sum_e);
printf("数学の合計点= %d\n",sum_m);
printf("英語の分散:%f\n", var_e);
printf("数学の分散:%f\n", var_m);
printf("英語の標準偏差:%f\n", sd_e);
printf("数学の標準偏差:%f\n", sd_m);
return 0;
}
実行結果
5人の点数を入力してください
[1] 英語:53
数学:82
[2] 英語:49
数学:35
[3] 英語:21
数学:72
[4] 英語:91
数学:35
[5] 英語:77
数学:12
英語の平均点= 58.20
数学の平均点= 47.20
英語の合計点= 291
数学の合計点= 236
英語の分散:584.960000
数学の分散:672.560000
英語の標準偏差:24.185946
数学の標準偏差:25.933762
なお、このプログラムは、Windows11のPCで、Visual Studio Code(バージョン: 1.87.1 (user setup))で動作確認している。
また、当初は、下記のようにコンパイルしたところ、エラーメッセージが出てコンパイルできなかった。
$ gcc sample.c
/usr/bin/ld: /tmp/cc48edvJ.o: in function `sd_of':
sample.c:(.text+0x1af): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
本プログラムでは、数学関数「sqrt」を利用するので、#include <math.h>
を先頭に記述している。
このmath.h内で関数の実行に失敗していると思われ、コンパイルオプションに「-lm」の指定をして実行してみたところうまくコンパイルできた。
$ gcc sample.c -lm
$
(参考)数学関数(超初心者向けプログラミング入門)
分散の求め方について
本プログラムでは、
「分散」を求めるときは、まず 「各データ」から「平均値」を引いて、2乗する 。そして、それらを 合計する 。さらに、その合計した値を、 全体の人数で割る 。
という方法で分散を計算している。高校の数学で習う範囲と思われる。
ところで、全体の人数をnとして、合計した値をnで割る方法以外に「n-1」で割る方法がある。
ネットで、本プログラムの「標準偏差」を検算したとき、「n-1」で割る方法で分散が計算された結果が出た。
筆者の専門外ではあるが、調べてみると、nで割る方法で分散を計算したものは、「母集団標準偏差(σ)」と呼ばれており、(n-1)で割った分散は不偏分散と呼ばれ、その平方根を取ったものが「サンプル標準偏差(s)」と呼ばれている。一般に「標準偏差」を計算すると、こちらで計算したものを指すということである。
(参考文献)新・明解C言語 入門編 第2版 柴田望洋著(SBクリエイティブ)新・解きながら学ぶC言語 第2版 柴田望洋・由梨かおる著(SBクリエイティブ)
コメント