1

In this answer on stackoverflow (answer #2) @remyabel recommends this template:

#include <random>

std::mt19937& prng_engine()
{
  thread_local static std::random_device rd{};
  thread_local static std::mt19937 engine{rd()};

  // Or you can replace the two previous lines with:
  //thread_local static std::mt19937
  //  prng{std::random_device{}()};

  return engine;
}

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
    thread_local static std::uniform_int_distribution<T> dist{Min, Max};
    return dist(prng_engine());
}

Will dist be created only once for give set of {T, Min, Max} in thread?

If I call it with (1, 10) and then with (11, 20) will it be recreated or not?

Community
  • 1
  • 1
vladon
  • 8,158
  • 2
  • 47
  • 91

2 Answers2

1

because it is static, dist is created only once - the first time code flows over it.

The first time code flows over it, the values of Min and Max will be 1 and 10.

On the second call, dist is not re-created so the new values of Min and Max are ignored and you get a random number between 1 and 10.

edit:

here's an implementation of getRandomNumberBetween that does what you want:

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
    using range_t = std::pair<T, T>;
    using map_t = std::map<range_t, std::uniform_int_distribution<T>>;
    static thread_local map_t range_map;

    auto i = range_map.find(range_t(Min, Max));
    if (i == std::end(range_map))
    {
        i = range_map.emplace(std::make_pair(Min, Max), std::uniform_int_distribution<T> { Min, Max}).first;
    }
    return i->second(prng_engine());
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
1

It will be created only once for every T (each instantiation of function template has its own copy of local static variables). You can check with:

std::cout << getRandomNumberBetween(0, 1) << '\n'
          << getRandomNumberBetween(10, 20) << '\n'
          << "------------------------\n"
          << getRandomNumberBetween('a', 'b') << '\n'
          << getRandomNumberBetween('c', 'z') << '\n';

Since distribution objects are lightweight, you can simply construct a new distribution when you need a random number (e.g. Vary range of uniform_int_distribution):

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
  std::uniform_int_distribution<T> dist{Min, Max};
  return dist(prng_engine());
}

However you can also consider this implementation:

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
  using distribution_type = std::uniform_int_distribution<T>;
  using param_type = typename distribution_type::param_type;

  thread_local std::uniform_int_distribution<T> dist;
  return dist(prng_engine(), param_type(Min, Max));    
}
Community
  • 1
  • 1
manlio
  • 18,345
  • 14
  • 76
  • 126
  • If `uniform_int_distribution` always recreated, how can it know that it uniformly generates numbers? – vladon May 07 '15 at 10:33
  • 1
    @vladon Random number engines generate pseudo-random numbers, distributions just post-process the output of a random number engine in such a way that result is distributed according to a defined statistical probability density function. Anyway it's true that in principle, a distribution object is allowed to store inside it some bits of entropy drawn from the generator on a previous call to `operator()` (e.g. http://stackoverflow.com/q/14857597/3235496) but I think it matters only using the same min/max values repeatedly. – manlio May 07 '15 at 10:45
  • so, theoretically, it is incorrect to recreate dist every time? – vladon May 07 '15 at 10:52
  • @vladon There are different opinions (e.g. http://stackoverflow.com/a/14858040/3235496). Anyway the second implementation doesn't recreate the distribution every time (it's from [N4316 - std::rand replacement](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4316.html) and should be safe). – manlio May 07 '15 at 11:00
  • 1
    @vladon Trying to get some insight on the matter, I've asked a new question about recreating distributions: http://stackoverflow.com/questions/30103356/distributions-and-internal-state. You can probably find something interesting there. – manlio May 08 '15 at 08:34