1

I have a short piece of code which runs the Mersenne Twister PRNG and it works great:

std::random_device randDev;
std::mt19937 twister(randDev());
std::uniform_int_distribution<int> dist(0,99);

for (int i = 0; i < 10; i++) {
    std::cout << dist(twister) << std::endl;
}

It outputs ten random numbers. However if I put the exact same code into a function:

#include <random>

int getRand(const int& A, const int& B) {
    std::random_device randDev;
    std::mt19937 twister(randDev());
    std::uniform_int_distribution<int> dist(A,B);

    return dist(twister);
}

int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << getRand(0,99) << std::endl;
    }

    return 0;
}

It outputs the same number ten times. I'm just starting out with C++ so I have no idea what causes this or how to go about fixing the problem.

EDIT: The problem lies with std::random_device. It could be a bug in Eclipse C++ IDE (Luna version) or MinGW 4.8.1 but for whatever reason that random number is always the same. I believe time(0) will be a suitable seed for my uses.

EDIT 2: Taking T.C.'s suggestion into account and the fact that time(0) still results in ten of the same number, here's the final code so far. I know rand() is bad but it works.

#include <iostream>
#include <random>

std::mt19937 twister(rand());

int getRand(const int& A, const int& B) {
    std::uniform_int_distribution<int> dist(A,B);

    return dist(twister);
}

int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << getRand(0,99) << std::endl;
    }

    return 0;
}

2 Answers2

3

The problem is that you create a brand new seed, random number generator and distribution every time the function is called. This is not the correct way to use these classes.

The proper way to use a random number generator is to create it once and use it as many times as you need for the entire program (or at least a reasonably long time). In the form of a single function:

#include <random>
#include <iostream>

int getRand(const int& A, const int& B) {
    static std::random_device randDev;
    static std::mt19937 twister(randDev());
    static std::uniform_int_distribution<int> dist;

    dist.param(std::uniform_int_distribution<int>::param_type(A, B));
    return dist(twister);
}

int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << getRand(0, 99) << std::endl;
    }

    return 0;
}

The static variables are initialized the first time the function is called and are re-used for all subsequent calls.

slajoie
  • 440
  • 8
  • 20
  • Thanks for improving my code, but the problem in this case it not the fact that I was recreating the seed but a bug with Eclipse or MinGW using std::random_device. – Demian Wright Jan 04 '15 at 13:08
  • 1
    The GCC random_device issue is well answered in the linked question. My answer is to the question you originally asked and may be useful to other people. – slajoie Jan 05 '15 at 22:45
0

What compiler and OS do you use? Visual Studio 2012 (not sure about 2013) didn't have a real implementation of std::random_device, which means that it was initialized with same value each time - so in such case you would have mersenne twister initialized with same seed each time, thus same result.

And by the way, seems that same question was asked in:

Why do I get the same sequence for every run with std::random_device with mingw gcc4.8.1?

so apparently GCC4.8 on Windows also has std::random_device implemented as pseudo-random.

Community
  • 1
  • 1
Tomasz Lewowski
  • 1,935
  • 21
  • 29