今度は中央値の計算も実装してみました。
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // qsortに必要
double mean(double d[],int n)
{
int i;
double sum = 0.0;
for( i=0 ; i<n ; i++ ){
sum += d[i];
}
return sum/n;
}
// qsort用の関数.qsortに渡せる形の関数を作成する必要がある.
// 仮引数や返り値の形式は指定されていることに注意.
int doublecmp(const void *a,const void *b){
return( *(double *)a - *(double *)b );
}
double median(double d[],int n)
{
int i;
double dCpy[n];
// コピーを作成するのは元データの順序保持のため
// 今回の統計量を計算するだけのコードでは不要ではあるが.
for( i=0 ; i<n ; i++ ){
dCpy[i] = d[i];
}
qsort(dCpy,n,sizeof(double),doublecmp);
if( n % 2 ){// 奇数
return dCpy[n/2];
}else{// 偶数
return (dCpy[n/2] + dCpy[n/2 -1])/2.0;
}
}
double min(double d[],int n)
{
int i;
int idx = 0; // 最小値の添字
for( i=0 ; i<n ; i++ ){
if( d[idx] > d[i] ){
idx = i;
}
}
return d[idx];
}
double max(double d[],int n)
{
int i;
int idx = 0; // 最大値の添字
for( i=0 ; i<n ; i++ ){
if( d[idx] < d[i] ){
idx = i;
}
}
return d[idx];
}
/*
double (*p[])(double [],int)={mean,median,min,max,NULL};
char *cp[]={"mean","median","min","max",NULL};
*/
typedef struct funcs{
double (*p)(double [],int);// 関数へのポインタ
char *cp;// 入力の文字列と比較する関数を表す文字列へのポインタ
}FUNCS;
FUNCS f[]={
{mean,"mean"},
{median,"median"},
{min,"min"},
{max,"max"},
{NULL,NULL}
};// ここで一元管理.最後のNULLは終端を示す番兵
double (*setfunc(char *str))(double d[],int n)
{
int i;
/*
for( i=0 ; cp[i] != NULL ; i++ ){
if( !strcmp(cp[i],str) ){
return p[i];
}
}
*/
for( i=0 ; f[i].cp != NULL ; i++ ){
if( !strcmp(f[i].cp,str) ){
return f[i].p;
}
}
printf("error in setfunc\n");
return NULL; // 入力の文字列が不適切な場合
}
int main(void)
{
double (*f)(double d[],int n);
double a[10]={0,1,2,3,4,5,6,7,8,19};
f = setfunc("mean");
printf("%lf\n",f(a,10));
f = setfunc("min");
printf("%lf\n",f(a,10));
f = setfunc("max");
printf("%lf\n",f(a,10));
return 0;
}
gccによるコンパイル後の実行結果は、以下の通り。
mean = 5.500000 median = 4.500000 min = 0.000000 max = 19.000000
構造体を用いて管理することによって、関数を表す文字列と関数がまとまり、
対応が分かりやすくなって、バグが出にくくなったのではないかと思う。
ライブラリのqsortを利用しているが、本来は全体をソートする必要はなく、
およそ途中までのソートができていれば良いので、そのあたりは工夫できるかも。
