2

いくつかの異なるメンバー メソッドで乱数を必要とするクラスがあります。私は使用C++11していますが、各メソッドで乱数ジェネレーターを新しく作成することは現実的ではないと思います。

乱数ジェネレーターをクラスのメンバー属性にするか、おそらく型定義にすることで、クラス全体で乱数ジェネレーターを共有することは可能ですか?

これを行うにはどうすればよいでしょうか。小さな例を教えていただけますか? Mersenne twisterランダム エンジンのシードをどこに設定すればよいですか。さまざまな種類の分布 ( normal& ) を持つエンジンを使用したいですuniform

4

2 に答える 2

6

エンジンとディストリビューションは値であり、値型を持つ他のオブジェクトと同様にメンバーにすることができます。

エンジンの作成時、つまりエンジンがメンバーの場合は、オブジェクトの構築時にエンジンをシードする必要があります。私の例では、クラス内イニシャライザを使用して、random_deviceデフォルトでエンジンをシードしています。また、再現可能でテスト可能な結果を​​得るために、シードを指定することもできます。

エンジンと対話するためのより完全なインターフェイスを提供するなど、実装の詳細を公開しすぎることは避けます。カプセル化が壊れるためです。これらは、実装の内部の隠された詳細である必要があります。

std::mt19937 make_seeded_engine() {
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    return std::mt19937(seed);
}

struct Foo {
    std::mt19937 eng = make_seeded_engine();
    std::uniform_int_distribution<> dist1 {1, 20};
    std::uniform_real_distribution<> dist2 {0.0, 100.0};

    Foo() = default;

    template<typename SeedSeq>
    Foo(SeedSeq &&seed) : eng(seed) {}

    int bar() {
        return dist1(eng);
    }

    double baz() {
        return dist2(eng);
    }    
};

ランダムなシーケンスが均一に分散されるという保証は、同じエンジン オブジェクトへの繰り返しの呼び出しのシーケンスに対してのみ保持されるため、少なくとも使用間でエンジンを保存する必要があります。異なるエンジンを使用して生成されたシーケンスについての保証はありません。

実際、同じことがディストリビューションにも当てはまりますが、毎回新しいディストリビューションを作成すると実際に誤った結果が生成される実装については知りません (ただし、さまざまな理由でディストリビューションが値をキャッシュする実装があるため、毎回ディストリビューションを作成すると、パフォーマンスが低下し、別のシーケンスが生成されます)。

たとえば、正規分布を計算するための一般的なアルゴリズムは、一度に 2 つの値を生成します。`std::normal_distribution の実装はこれを行い、他のすべての呼び出しを使用するために 2 番目の値をキャッシュします。次のプログラムはこれを示しています。

#include <iostream>
#include <random>

int main() {
    typedef std::mt19937 Engine;
    typedef std::normal_distribution<> Distribution;
    Engine eng(1);
    Distribution dist;

    for (int i=0; i<10; ++i)
        std::cout << dist(eng) << ' ';
    std::cout << '\n';

    eng.seed(1);
    for (int i=0; i<10; ++i)
        std::cout << Distribution()(eng) << ' ';
    std::cout << '\n';
}

VC++2012 を使用すると、次の出力が得られます。

0.156066 0.3064 -0.56804 -0.424386 -0.806289 -0.204547 -1.20004 -0.428738 -1.18775 1.30547
0.156066 -0.56804 -0.806289 -1.20004 -1.18775 -0.153466 0.133857 -0.753186 1.9671 -1.39981

反復ごとに新しい分布を作成するときに生成されるシーケンスには、単一の分布で生成されたシーケンスの他のすべての値のみが含まれることに注意してください。

于 2013-05-30T17:13:14.470 に答える