Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I generate thread-safe uniform random numbers?

My program needs to generate many random integers in some range (int min, int max). Each call will have a different range. What is a good (preferably thread-safe) way to do this? The following is not thread-safe (and uses rand(), which people seem to discourage):

int intRand(const int & min, const int & max) {     return (rand() % (max+1-min)) + min; } 

This is much slower, but uses <random>:

int intRand(const int & min, const int & max) {     std::default_random_engine generator;     std::uniform_int_distribution<int> distribution(min,max);     return distribution(generator); } 

Something like this is what I'm going for (the changeParameters function doesn't exist though):

int intRand(const int & min, const int & max) {     static std::default_random_engine generator;     static std::uniform_int_distribution<int> distribution(0, 10);     distribution.changeParameters(min, max);     return distribution(generator); } 

Another option would be to make a wide range on the uniform_int_distribution and then use mod like in the first example. However, I'm doing statistical work, so I want the numbers to come from as unbiased of a distribution as possible (e.g., if the range of the distribution used is not a multiple of (max-min), the distribution will be slightly biased). This is an option, but again, I would like to avoid it.

SOLUTION This solution comes from the answers by @konrad-rudolph @mark-ransom and @mathk . The seeding of the random number generator is done to suit my particular needs. A more common approach would be to use time(NULL). If you make many threads in the same second, they would then get the same seed though. Even with clock() this is an issue, so we include the thread id. A drawback - this leaks memory --- one generator per thread.

#if defined (_MSC_VER)  // Visual studio     #define thread_local __declspec( thread ) #elif defined (__GCC__) // GCC     #define thread_local __thread #endif  #include <random> #include <time.h> #include <thread>  using namespace std;  /* Thread-safe function that returns a random number between min and max (inclusive). This function takes ~142% the time that calling rand() would take. For this extra cost you get a better uniform distribution and thread-safety. */ int intRand(const int & min, const int & max) {     static thread_local mt19937* generator = nullptr;     if (!generator) generator = new mt19937(clock() + this_thread::get_id().hash());     uniform_int_distribution<int> distribution(min, max);     return distribution(*generator); } 
like image 486
PThomasCS Avatar asked Jan 20 '14 15:01

PThomasCS


People also ask

How do you generate random uniform numbers?

The inversion method relies on the principle that continuous cumulative distribution functions (cdfs) range uniformly over the open interval (0,1). If u is a uniform random number on (0,1), then x = F - 1 ( u ) generates a random number x from any continuous distribution with the specified cdf F .

Is random number generator thread safe?

Both the functions on the “random” module are thread safe as are the methods on an instance of the random. Random class. This means that a multithreaded program may call module functions in order to generate random numbers with a seed and sequence of random numbers shared between threads, or have a single new random.

What is uniform random number generator?

The Uniform Random Number block generates uniformly distributed random numbers over a specifiable interval with a specifiable starting seed. The seed is reset each time a simulation starts. The generated sequence is repeatable and can be produced by any Uniform Random Number block with the same seed and parameters.

Do random number generators have a pattern?

But good random number generators don't have any clear pattern to their output, making finding which page of their codebook they correspond to very difficult.) There is no limit to the size of the codebook that algorithmic random number generation can support.


2 Answers

Have you tried this?

int intRand(const int & min, const int & max) {     static thread_local std::mt19937 generator;     std::uniform_int_distribution<int> distribution(min,max);     return distribution(generator); } 

Distributions are extremely cheap (they will be completely inlined by the optimiser so that the only remaining overhead is the actual random number rescaling). Don’t be afraid to regenerate them as often as you need – in fact, resetting them would conceptually be no cheaper (which is why that operation doesn’t exist).

The actual random number generator, on the other hand, is a heavy-weight object carrying a lot of state and requiring quite some time to be constructed, so that should only be initialised once per thread (or even across threads, but then you’d need to synchronise access which is more costly in the long run).

like image 145
Konrad Rudolph Avatar answered Sep 28 '22 05:09

Konrad Rudolph


Make the generator static, so it's only created once. This is more efficient, since good generators typically have a large internal state; more importantly, it means you are actually getting the pseudo-random sequence it generates, not the (much less random) initial values of separate sequences.

Create a new distribution each time; these are typically lightweight objects with little state, especially one as simple as uniform_int_distribution.

For thread safety, options are to make the generator thread_local, with a different seed for each thread, or to guard it with a mutex. The former is likely to be faster, especially if there's a lot of contention, but will consume more memory.

like image 40
Mike Seymour Avatar answered Sep 28 '22 03:09

Mike Seymour