ストリームイテレータ
しばしば,実験データから何らかの統計値(平均,分散,...)を求めたい場合があります.今回も, RMSE(Root Mean Square Error:平均2乗平方根誤差)を求めなければならない場面に遭遇しました. それで,せっかくなので汎用的に使える関数として残しておこうと思い,以下のような関数を書きました.
template <class InputIterator, class Type>
double mse(InputIterator first, const InputIterator& last, Type correct) {
double sum = 0.0;
unsigned int n = 0;
while (first != last) {
double tmp = *first++ - static_cast<double>(correct);
sum += std::pow(tmp, 2);
n++;
}
return sum / static_cast<double>(n);
}
template <class InputIterator, class Type>
double rmse(InputIterator first, const InputIterator& last, Type correct) {
return std::sqrt(mse(first, last, correct));
}
使い方としては,rmse < test.datのようにデータファイルをリダイレクトで渡すような形を考えていました. それで,メインプログラムをどのような形で書こうかな,と.最初に思いついたのは, streambuf_iterator を使う方法だったのですが,これだと一文字づつ読み込んでしまい(100 200 300の場合,'1','0','0',' ','2',...) 期待した動きをしてくれませんでした.しばらくWebを彷徨っていたところ, stream_iterator を利用すればうまくいく模様(100 200 300の場合,"100","200","300"). そういう訳で,最終的なプログラム.
int main(int argc, char* argv[])
{
if (argc < 2) exit(-1);
int correct = std::atoi(argv[1]);
std::istream_iterator<double> input(std::cin);
std::istream_iterator<double> last;
double val = rmse(input, last, correct);
std::cout << "RMSE: " << val << std::endl;
return 0;
}