Stream Iterator
Home >> Note >> Stream Iterator

ストリームイテレータ

しばしば,実験データから何らかの統計値(平均,分散,...)を求めたい場合があります.今回も, 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;
}