简体   繁体   English

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

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

I have a class which needs random numbers in a couple of different member methods. 我有一个类,需要在几个不同的成员方法中随机数。 I'm using C++11 and I think it is not feasible to newly create a random number generator in each method. 我正在使用C++11 ,我认为在每种方法中重新创建随机数生成器是不可行的。

Is it possible to share the random number generator across the class by making it a member attribute of the class or maybe a typedef, while still ensuring good randomness ? 是否可以通过使其成为类的成员属性或类型def来共享整个类中的随机数生成器,同时仍然确保良好的随机性

How would I does this, maybe you can point me to a small example? 我怎么能这样做,也许你可以给我一个小例子? Where should I set the seed for the random engine, I want to use a Mersenne twister engine with different types of distributions ( normal & uniform ). 我应该在哪里设置随机引擎的种子,我想使用具有不同类型分布( normaluniform )的Mersenne twister引擎。

Engines and distributions are values and can be members just like other objects with value types. 引擎和分布是值,可以像其他具有值类型的对象一样成为成员。

You should seed the engine when it is created, which means, if it's a member, when your object is constructed. 您应该在创建引擎时播种引擎,这意味着,如果它是成员,则构造对象。 My example uses an in-class initializer with random_device to seed the engine by default. 我的示例使用带有random_device的类内初始化random_device来默认为引擎random_device种子。 It also allows the seed to be specified, for reproducible, testable results. 它还允许指定种子,以获得可重复的,可测试的结果。

I would avoid exposing too much of the implementation details, such as providing a more complete interface for interacting with the engine, as that breaks encapsulation. 我会避免暴露太多的实现细节,例如提供一个更完整的界面来与引擎交互,因为这打破了封装。 These should be internal, hidden details of the implementation. 这些应该是实现的内部隐藏细节。

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);
    }    
};

You need to at least store the engine between usages, because the guarantees for a random sequence to be uniformly distributed only hold for sequences of repeated calls to the same engine object. 您至少需要在用法之间存储引擎,因为对随机序列进行均匀分布的保证仅适用于重复调用同一引擎对象的序列。 There's no guarantee about a sequence produced by using different engines. 无法保证使用不同引擎生成的序列。

And in fact the same is true of distributions, although I don't know of implementations where creating a new distribution each time would actually produce incorrect results (there are implementations where distributions cache values for various reasons, however, so creating distributions every time could perform worse and produce a different sequence). 实际上,发行版也是如此,尽管我不知道每次创建新发行版的实现实际上都会产生不正确的结果的实现(有些实现中,发行版出于各种原因缓存值,因此每次创建发行版都可能表现更差并产生不同的序列)。

For example, the common algorithm for computing a normal distribution produces two values at once. 例如,用于计算正态分布的通用算法一次产生两个值。 Implementations of `std::normal_distribution do this and cache the second value to use every other call. `std :: normal_distribution的实现执行此操作并缓存第二个值以使用每个其他调用。 The following program exhibits this. 以下程序展示了这一点。

#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';
}

With VC++2012 I get the output: 使用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

Notice that the sequence produced when creating a new distribution every iteration contains only every other value of the sequence produced with a single distribution. 请注意,每次迭代创建新分布时生成的序列仅包含使用单个分布生成的序列的每个其他值。

Is it possible to share the random number generator across the class by making it a member attribute of the class or maybe a typedef, while still ensuring good randomness? 是否可以通过使其成为类的成员属性或类型def来共享整个类中的随机数生成器,同时仍然确保良好的随机性?

Absolutely. 绝对。 Provided that you initialize it with a varying seed (or let it use the default), you should get "good" randomness each time you call the RNG. 如果您使用不同的种子初始化它(或让它使用默认值),每次调用RNG时都应该获得“良好”的随机性。 In fact, I would suggest that using a separate RNG for each method is not only costly, but a bad design. 事实上,我建议为每种方法使用单独的RNG不仅成本高昂,而且设计糟糕。

As for how to implement various distributions, http://en.cppreference.com/w/cpp/numeric/random has some good examples (such as this one ). 至于如何实现各种发行版, http://en.cppreference.com/w/cpp/numeric/random有一些很好的例子(比如这个 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM