Fareanor
Fareanor

Reputation: 6805

How to seed a random number generator in a safe and portable way?

Background:

Since , it is recommended to use a std::random_device instead of the time to seed a random number generator. If we take a look at the related documentation, we can read that:

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.

emphasis mine

Let's now consider the following example:

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution distr(0, 9);

    // Print a sequence of 10 uniformly distributed random integers
    for(std::size_t i = 0; i < 10; ++i)
        std::cout << distr(gen) << ' ';

    return 0;
}

If the system/platform does not provide a non-deterministic source, this program may/will always generate the same sequence of numbers for each run (it is actually the case on my platform).

In this case, std::random_device is far worse than seeding the random number generator with the current time:

std::mt199937 gen(std::chrono::high_resolution_clock::now().time_since_epoch().count()); // time seed

Issue:

My concern is that if someone wants to write a program that will rely on some random generated numbers and is required:

  1. To be portable
  2. To guarantee non-deterministic randomness

Then std::random_device will not be a right fit.
On the other hand, using always a time seed would be a quite frustrating "solution" since if the given platform has a non-deterministic source available, std::random_device would then be "safer".

Question:

My question is divided in two parts:

  1. Userland
    • Is there a portable way to check if such a non-deterministic source is available on the current platform?
  2. Compiler-side
    • Are compilers allowed to replace std::random_device seeds by time seeds if the host platform has no non-deterministic source available ? Or is there something in the standard that would prevent such a replacement?
    • If the standard does not prohibit this behaviour, what would be a reason for compilers to not implement it?

Perhaps these should be 2 or 3 separate questions. Since the background and issue are common, I've asked them in the same post for completeness purposes on the topic. Please let me know if I have to split them into separate questions anyway.

Upvotes: 5

Views: 2219

Answers (1)

NathanOliver
NathanOliver

Reputation: 180500

Is there a portable way to check if such a non-deterministic source is available on the current platform?

You can use the entropy member function of std::random_device to check if the source is non-deterministic or not. Unfortunately it is not a static constexpr function so you'll have to use a regular if statement like

int main()
{
    std::random_device rd;
    std::size_t seed;
    if (rd.entropy())
        seed = rd();
    else
        seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
    std::mt19937 gen(seed);
    std::uniform_int_distribution distr(0, 9);

    // Print a sequence of 10 uniformly distributed random integers
    for(std::size_t i = 0; i < 10; ++i)
        std::cout << distr(gen) << ' ';

    return 0;
}

Are compilers allowed to replace std::random_device seeds by time seeds if the host platform has no non-deterministic source available ? Or is there something in the standard that would prevent such a replacement?

That would change the observable behavior of the program so no, the compiler can't do that.

Upvotes: 3

Related Questions