I am trying to encapsulate a class to generate random numbers controlling by seed and by the range of random values. I want to call this class from different parts of my codes, with different ranges, but using the same seed.
Following suggestions of other post (Encapsulated Random number generator in C++-11 using boost) I implemented the following code:
My Random Number Generator class:
    #include <random>
    #include <iostream>
    typedef std::mt19937                     ENG;    // Mersenne Twister
    typedef std::uniform_int_distribution<> iDIST;   // Uniform Integer Distribution
    class RNG {
      private:
         ENG eng;
         iDIST idist;
      public:
         iDIST::result_type igen() { return idist(eng); }
         RNG(ENG eng_,int imin,int imax)
         : idist(imin,imax)
         {eng = eng_; }
    };
A function to create an object of RNG class and print the random values:
    void myfunc(ENG eng_,int imin, int imax, int N){
        RNG myirn(eng_,imin,imax);
        for (int i = 0; i < N; i++){
            std::cout << myirn.igen() << std::endl;
        }
        return;
    }
My main function:
    int main(int argc, char **argv){
        int myseed = 1;
        int N = 5;
        int imin1 = 1;
        int imax1 = 10;
    //Seed globally
        ENG eng_;
        eng_.seed(myseed);
        std::cout << "Range = [" << imin1 << "," << imax1 << "]" << std::endl;
        myfunc(eng_,imin1,imax1,N);
        std::cout << "Range = [" << imin1 << "," << imax1 << "]" << std::endl;
        myfunc(eng_,imin1,imax1,N);
    return 0;
    }
As you can see, my strategy was to seed my random number generator globally (in the main function) and pass the variable eng_ as a parameter to the function func, that will instantiate the RNG object and print the random values. If everything were correct, this code should print 2 sequences of 5 random numbers within the same range but with different values. However, they are exactly the same sequence. Could anyone help me to fix this?
Since you want to use the same engine, you have to use the same engine. (That much is a singleton.) Pass a reference to RNG, store and use a reference within RNG. Minor changes to your code make this so (one of the comments already pointed this out):
ENG ŋ
RNG(ENG &eng_, int imin, int imax)
    : idist(imin, imax), eng(eng_) {}
void myfunc(ENG &eng_, int imin, int imax, int N)
But I like it better if the engine is hidden in RNG like this:
class RNG {
private:
    static ENG eng;
    iDIST idist;
public:
    static void seed(int s) { eng.seed(s); }
    RNG(int imin, int imax) : idist(imin, imax) {}
    int generate() { return idist(eng); }
};
// the one generator, stored as RNG::eng
ENG RNG::eng;
// print some generated numbers from a range
void printRandomNumbers(int imin, int imax, int N){
    std::cout << "Range = [" << imin << "," << imax << "]" << std::endl;
    RNG myirn(imin, imax);
    for (int i = 0; i < N; i++){
        std::cout << myirn.generate() << std::endl;
    }
    return;
}
int main()
{
    //Seed globally
    int myseed = 1;
    RNG::seed(myseed);
    printRandomNumbers(1, 10, 5);
    printRandomNumbers(11, 20, 5);
    printRandomNumbers(21, 30, 5);
    return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With