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

fuj*_*uji 2 c++ random distribution c++11

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

是否可以通过使其成为类的成员属性或类型def来共享整个类中的随机数生成器,同时仍然确保良好的随机性

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

bam*_*s53 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);
    }    
};
Run Code Online (Sandbox Code Playgroud)

您需要至少将引擎存储在用法之间,因为随机序列的均匀分布保证仅适用于对同一引擎对象的重复调用序列.无法保证使用不同引擎生成的序列.

事实上,对于发行版也是如此,虽然我不知道每次创建新发行版实际上会产生不正确结果的实现(但是,由于各种原因,发行版会分配缓存值,因此每次都可以创建发行版表现更差并产生不同的序列).

例如,用于计算正态分布的通用算法一次产生两个值.`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';
}
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

请注意,每次迭代创建新分布时生成的序列仅包含使用单个分布生成的序列的每个其他值.

  • @j.dog在我的例子中,我默认使用`random_device`生成种子,但也允许用户提供种子.我这样做只是为了使对象允许作为选项,用于测试,调试等的确定性,可重现的结果. (2认同)