2

I get a task to generate tens of thousands random number in c++. I've googled a lot about random number in c++ and look up the c++ reference, but I got confused now.

As I know, random_device is a non-deterministic random number generator, but every time I re-run my program, the random number generated by random_device is the same. So how do I set a seed for random_device to make the random number is different when I restart my program?

And I've read that "std::random_device could run out of entropy if you try to get a lot of numbers from it. That could cause it to block until you move the mouse or something". That means my program could pause at some time. How can I avoid this happening?

  • What compiler are you using? `std::random_device` is ***broken*** in `MinGW`. – Galik Dec 14 '18 at 03:36
  • I am using GNU or g++ under ubuntu. – user5667679 Dec 14 '18 at 04:17
  • Can you post some short example code that reproduces the problem? – Galik Dec 14 '18 at 04:42
  • 1
    I think this answer may answer some of your question: https://stackoverflow.com/questions/50662280/c-need-a-good-technique-for-seeding-rand-that-does-not-use-time/50665027#50665027 – Galik Dec 14 '18 at 04:49
  • Why do you need a different set for each program run? – Bathsheba Dec 14 '18 at 08:17
  • "And I've read that "std::random_device could run out of entropy if you try to get a lot of numbers from it. That could cause it to block until you move the mouse or something". That means my program could pause at some time. How can I avoid this happening?" - is your target architecture a ZX81? – Bathsheba Dec 14 '18 at 08:22

2 Answers2

1

From here, you can see std::random_device does not always guarantee to be non-deterministic:

std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.

On Linux, it by default uses /dev/urandom or RDRND CPU instruction according to here:

The implementations in libc++ and libstdc++ expect token to be the name of a character device that produces random numbers when read from, with the default value "/dev/urandom", although where the CPU instruction RDRND is available, libstdc++ uses that as the default.

which won't block. You can switch to a even secured device /dev/random using approach here, but that device will block if not having enough entropy.

On Windows, I'm not sure about such device therefore it might fall back to some PRNG which requires some kind of seed.

To solve the problem cross-platformly, as @Binara mentioned, you can use std::rand from <cstdlib>. This function will not block, and you can use std::srand(somethingLikeCurrentTime) to make it some-what non-deterministic.

As @user1118321 mentioned, if you want to use a more secured PRNG, you might consider std::mersenne_twister_engine and use std::random_device to generate a seed of it. This approach is suggested here.

ZisIsNotZis
  • 1,570
  • 1
  • 13
  • 30
1

Assuming you don't need cryptographically secure random number generation, then you can use the std::mt19937 random generator. It's the Meresenne Twister random generator that has a period of 219937 iterations before it repeats. I've used it like this in the past:

std::array<int, std::mt19937::state_size> seedData;
std::random_device  randDevice;
std::mt19937 eng;
std::uniform_real_distribution<double> randGen(0, 1);
std::generate_n(seedData.data(), seedData.size(), std::ref(randDevice));
std::seed_seq seq(std::begin(seedData), std::end(seedData));
eng.seed(seq);

That creates an array containing the seed of the appropriate size. It creates a random device to set up the seed. Then it creates an mt19937 random generator engine to generate the numbers. To use it to generate values between 0 and 1 you can use the std::uniform_real_distribution like this:

double randVal = randGen(eng);
user1118321
  • 25,567
  • 4
  • 55
  • 86