平均を求める

単純な方法



例えばデータを100個あるいは1000個程度測定し、その平均を求めるとします。期待値が500とするとデータが100個の場合、加算値は50000になります。この値は16bitの整数型ではオーバーフローするので使えません。従って変数はlongかfloat型を用いなければいけません。
配列を用いる
int data[100];
float sum=0;
int i;
for(i=0; i<100; i++) {
  data[i] = getData();
}
for(i=0; i<100; i++) {
  sum += data[i];
}
sum /=100; 


配列を使わない

 上記のようにすると、一回しか使わない配列を利用するのでメモリの無駄になります。従って配列を使うのは賢くないことになります。ですから、データを測定しながら平均を計算するようにします。

配列を使わない
float sum=0;
int i;
for(i=0; i<100; i++) {
  sum += getData();
}
sum /=100; 


配列とfloatを使わない

 上記のようにすると、一見よいように思われます。しかし、floatあるいはlongのライブラリは大きいのでやはりメモリの無駄になります。また、計算時間もかかります。メモリ容量の少ないCPUではできる限りfloat演算を行ってはいけません。全てをint演算にします。しかし、一番始めの議論からオーバーフローするので無理になります。ここで頭を使います。全部加算するからオーバーフローするのです。そもそも、あやふやな値の平均なので多少あやふやな答えになっても問題がないことに気が付くべきです。ADコンバーターで測定した白の値の約半分か1/3の値を閾値にするのですから、大体の平均が求まればいいので問題はありません。
 次のような、式を用いると数が多くなると平均値に近くなります。αは0.9とか0.95あたりがよいかと思います。
 yi = αyi-1 + (1-α)xi
しかし、この式を適用するにはやはりfloat演算が必要になります。ここでまた頭を使います。αを0.9とする場合を考えるとデータを9倍してから10で割れば0.9を掛けたと同じことになります。整数演算なので多少の誤差は起こりますが、大体の値なので問題ありません。従って次式のようになります。
  yi = (9×yi-1 + xi)/10
αを0.95にする時には、
  yi = (95×yi-1 + 5×xi)/100
つまり、
  yi = (19×yi-1 + xi)/20
このようにすれば、メモリも少量で高速に平均を求めることが分かります。

配列とfloatを使わない
 自分で考えましょう。