Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to instantiate c++11 random facilities

After looking a various examples on the uses of the new 'random' facilities in C++, I'm left a little confused as to best practices - specifically related to lifetimes of various instances.

For instance in some examples the use of "random_device" is either static in a local scope like a function, or is a static global variable or is just plainly a local.

--- TU ---

static std::random_device global_source;


void foo()
{
   static std::random_device local_static_source;
   static std::mt19937 gen(local_static_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
}

void boo()
{
   std::mt19937 gen(global_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
}

void roo()
{
   std::random_device local_source;
   std::mt19937 gen(local_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
}

int main()
{
   static std::mt19937 gen(global_source());
   std::uniform_int_distribution<> dist(0,10);
   ...
   dist(gen);
   ...
  return 0;
}

--- TU ---

Q1: If "foo" or "boo" can be accessed by multiple threads, is it ok to have the generator and source be static? - is there any kind of thread safety guarantees like those in shared_ptr?

Q2: Is there any wording in the standard that discusses assumptions and issues related to instantiation?

like image 635
Gerdiner Avatar asked Feb 28 '14 02:02

Gerdiner


People also ask

How do you generate a random number in C?

The rand() and srand() functions are used to generate random numbers in C/C++ programming languages. The rand() function gives same results on every execution because the srand() value is fixed to 1.

How do you initialize a random number in C++?

One way to generate these numbers in C++ is to use the function rand(). Rand is defined as: #include <cstdlib> int rand(); The rand function takes no arguments and returns an integer that is a pseudo-random number between 0 and RAND_MAX.

How do you generate a random number with a range in C++?

How to Generate Random Numbers in C++ Within a Range. Similar to 1 and 10, you can generate random numbers within any range using the modulus operator. For instance, to generate numbers between 1 and 100, you can write int random = 1+ (rand() % 100).

How do you generate a random number between 1 and 10 in C++?

rand() function generates random number and when you use rand()%10 , it will give you last digit of the number. Since we require random number between 1 and 10, we have used rand()%10+1 to generate random number between 1 and 10 in C++.


1 Answers

Some background: the reasons for allowing multiple instances of random number generators are mainly thread safety (not burdening random number generator implementations with thread synchronization) and repeatability (allowing a sequence of numbers to be repeated using the same seed).

  • The former is pretty self-explanatory - there are valid cases for using RNGs in performance-critical code. With multiple instances possible, there is no expensive mutex required and random numbers can be generated on multiple CPU cores in parallel.

  • The latter is generally useful when generating data sets by random. As a common example, video games may recreate the same (random) game world by driving all decisions related to the creation of the game world from the same RNG (possibly even on different networked PCs).

So the best scope for a C++ RNG depends on what you're writing:

If you're writing a library that might be used in the context of the above to scenarios, it is probably a good idea to let the caller provide the RNG to the individual methods or classes:

// Can be used on multiple CPU cores in parallel or with seed values
template <typename TRandomNumberEngine>
Point2 GetRandomPointInRectangle(
  const Rectangle2 &rect, TRandomNumberEngine &random
) {
  std::uniform_real_distribution<float> horizontal(rect.Min.X, rect.Max.X);
  float x = horizontal(random);

  std::uniform_real_distribution<float> vertical(rect.Min.Y, rect.Max.Y);
  float y = vertical(random);

  return Point2(x, y);
}

If you're writing an application or a library that uses the RNG in a supporing role (eg. geometric fitting algorithms), ie. you're just interested in non-repeatable random numbers, the best scope for a random number generator would be the largest possible scope that doesn't introduce unwanted coupling between modules.

That could be a simple private object variable in whatever class needs random numbers or even a thread_local singleton providing the RNG of your choice if it has a lot of short-lived consumers that justify such complexity.


The distributions (like std::uniform_real_distribution) can be as short-lived as you want. They're plain functors where the constructor either has no arguments or only stores the arguments for when the functor gets executed.

like image 112
Cygon Avatar answered Oct 27 '22 00:10

Cygon