Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How often should I reseed in C++?

Tags:

c++

c++11

I just wonder if it is enough to seed the random number generator only once at the beginning of a program. I write functions which uses random numbers. I never seed the rand() generator within the function, but rather leave calling srand() on main entry. E.g. my program may look like:

void func1()
{
    std::cout << "This is func1 " << std::rand() << std::endl;
}

void func2()
{
    std::cout << "This is func2 " << std::rand() << std::endl;
}

int main()
{
    std::srand(std::time(NULL));
    func1();
    func2();
    return 0;
}

By doing so, I can easily switch off seeding from the main entry. It comes useful when debugging a program - the results are kept the same every time I run the program without seeding. Sometimes, if a problem occurs due to some random number, it may just disappear if a different set of random numbers is to be generated, so I'd prefer such a simple mechanism to switch off seeding.

However, I noticed in C++11's new random utility set, the random number generator has to be instantiated before using. (e.g. default_random_engine). And every time a generator has to be seeded separately. I wonder if it is actually encouraged to reseed the generator whenever a new generator is needed. I know I could create a global random generator and seed it only once as before, but I don't really like the idea of using global variables at all. Otherwise, if I create a local random number generator, I sort of lose the ability to globally switch off seeding for debugging or whatever purpose.

I'm excited to learn the new features in C++11, but sometimes it's just very confusing. Can anyone let me know if I got anything wrong with the new random generators? Or what might be the best practice in C++11?

like image 789
xing_yu Avatar asked Mar 03 '13 06:03

xing_yu


2 Answers

This would definitely depend on the overall goals of the system you are developing, but in general you will only need to seed any system that requires a Random number generator (RNG) once at initialization of that system.

In game development it is common to have a separate RNG per system (AI, Procedural content generators, particles, etc.) to isolate that system for debugging and maintenance.

If you store the seeds you can also replay the logic with very little data (only requiring delta inputs from each frame). This not only allows you to debug the application easier, but also allows you to support recording and replay features for the user. Obviously if you were creating a replay mode, the system would need to be supplied with a recorded seed for each of the systems prior to every replay session.

There are other systems such as Cryptography where you may want to establish a new seed periodically. You may want to expire a seed over time or require a new seed to be generated per handshake with a client application. However, you will likely want to utilize a Cryptography library as they will likely be far more robust then something you would roll your own.

like image 119
Matthew Sanders Avatar answered Sep 19 '22 14:09

Matthew Sanders


One of the reasons for having a random number generator (RNG) require instantiation is so that it can keep its state internal, that way in a multi-threaded application you don't introduce non-determinism when multiple threads use the same RNG with process-global state. Suppose you have two threads, each working on independent parts of a problem - if the state (seed) is private to the RNG instance then you can have determinism when you seed each thread's RNG with a known value. On the other hand, if the RNG keeps state in a global variable then the sequence of random numbers observed by each thread depends on the inter-leaving of their calls to the RNG - you've now introduced non-determinism.

One programming pattern that is used to assign work in multi-threaded applications is a thread pool. If the work items that are queued up for worker threads in the pool to execute require an RNG and you want execution to be deterministic from run to run, then you want each thread to re-seed the RNG after pulling a new work item from the queue

  • this can be done as part of the initialization for the work item
  • the seed might involve a hash function of parameters for the job
  • if you are careful about how this is coded you can have pseudo-randomness and determinism regardless of the number of worker threads or the order in which they pull jobs off the queue.

Here's an SO question that deals with this: Deterministic random number generator tied to instance (thread independent)

In a single-threaded application it is not necessary to re-seed an RNG, and in fact it is undesirable because by doing that you shorten it's cycle before it will start repeating. The exception to this is what @MatthewSanders pointed out, Cryptography - in that case you want maximum entropy (least determinism) because random numbers are used as private keys.

like image 35
amdn Avatar answered Sep 20 '22 14:09

amdn