简体   繁体   中英

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.

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 ?

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 ).

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. 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. 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:

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?

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. In fact, I would suggest that using a separate RNG for each method is not only costly, but a bad design.

As for how to implement various distributions, http://en.cppreference.com/w/cpp/numeric/random has some good examples (such as this one ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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