c++11中在类中的不同方法之间共享random_number_engine

share random_number_engine between different methods within a class in c++11

本文关键字:random 共享 number engine 之间 c++11 方法      更新时间:2023-10-16

我有一个类,在几个不同的成员方法中需要随机数。我使用的是C++11,我认为在每种方法中新创建一个随机数生成器是不可行的。

是否有可能通过使其成为类的成员属性或类型定义来跨类共享随机数生成器,同时仍然确保良好的随机性?

我该怎么做呢,也许你可以给我举个小例子?我应该在哪里为随机引擎设置种子,我想使用具有不同类型分布的Mersenne twister引擎(normal &uniform)。

引擎和分布都是值,可以像其他具有值类型的对象一样作为成员。

你应该在引擎被创建的时候播种,这意味着,如果它是一个成员,在你的对象被构造的时候播种。我的例子在默认情况下使用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);
    }    
};

您至少需要在使用之间存储引擎,因为保证随机序列均匀分布只适用于对同一引擎对象的重复调用序列。不能保证使用不同的引擎产生的序列。

实际上分布也是如此,尽管我不知道每次创建一个新的分布实际上会产生不正确的结果(有些实现中分布由于各种原因缓存值,但是,每次创建分布可能会表现得更差,并且产生不同的序列)。

例如,计算正态分布的常用算法一次产生两个值。`std::normal_distribution `的实现做到了这一点,并缓存第二个值以在每次其他调用时使用。下面的程序展示了这一点。

#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

请注意,每次迭代创建新分布时产生的序列只包含单个分布产生的序列的所有其他值。

是否有可能通过使其成为类的成员属性或类型定义来跨类共享随机数生成器,同时仍然确保良好的随机性?

绝对。如果您使用不同的种子初始化它(或让它使用默认值),则每次调用RNG时都应该获得"良好"的随机性。事实上,我建议为每种方法使用单独的RNG不仅成本高,而且是一个糟糕的设计。

关于如何实现各种发行版,http://en.cppreference.com/w/cpp/numeric/random有一些很好的例子(比如这个)。