4

乱数の平均を計算する 2 つのアルゴリズムを比較していました。

  • 最初のアルゴリズムはすべての数値を合計し、最後にアイテム数で割ります
  • 2 番目のアルゴリズムは、反復ごとに平均を計算し、新しいデータを受信したときに結果を再利用します。

ここには革新的なものは何もないと思います。私は数学者ではないので、これら 2 つのアルゴリズムに名前を付けることはできません。

これが私のコードです:

#include <iostream>
#include <iomanip>
#include <cstdlib>

class Average1
{
public:
    Average1() : total( 0 ), count( 0 ) {}

    void add( double value )
    {
        total += value;
        count++;
    }

    double average()
    {
        return total/count;
    }

private:
    double total;
    size_t count;
};

class Average2
{
public:
    Average2() : av( 0 ), count( 0 ) {}

    void add( double value )
    {
        av = (av*count + value)/(count+1);
        count++;
    }

    double average()
    {
        return av;
    }

private:
    double av;
    size_t count;
};

void compare()
{
    Average1 av1;
    Average2 av2;
    double temp;
    for ( size_t i = 0; i != 100000000; ++i )
    {
        temp = static_cast<double>(std::rand()) / static_cast<double>(RAND_MAX);
        av1.add( temp );
        av2.add( temp );
    }

    std::cout << std::setprecision(20) << av1.average() << std::endl;
    std::cout << std::setprecision(20) << av2.average() << std::endl;
}

int main()
{
    compare();
    return 0;
}

出力は次のとおりです。

0.50001084285722707801
0.50001084285744978875

違いは確かにdouble型の精度によるものです。

結局、どの方法がいいの?実際の数学的平均 (またはそれに最も近い) を与えるのはどれですか?

4

4 に答える 4

8

本当に高精度が必要な場合:

編集: math.fsum の python-docs も、このアプローチの概要にリンクしています

于 2016-05-25T19:49:26.500 に答える
3

私の推測では、最初のクラスの方がより信頼できる結果が得られると思います。2 番目のケースでは、各反復で、カウントによる除算による概算を行い、最終的にこれらすべての概算を合計すると、表示される結果の差が生じます。代わりに、最初のケースでは、最終的な除算を計算するときに近似するだけです。

于 2016-05-25T19:49:18.413 に答える
0

私自身の考えでは、どちらもそれを除算する前に大きな数である count 回の値を計算するため、結果が概算である理由が説明されます。私はするだろう:

class Average3
{
public:
    Average3() : av( 0 ), count( 0 ) {}

    void add( double value )
    {
        count++;
        av +=  (value - av)/count;
    }
...

ただし、値/カウントの追加は平均に比べて小さいため、最後の数値を追加すると精度が失われます。私の直感が正しかったかどうかを教えていただければ幸いです

于 2016-05-25T20:18:07.810 に答える