1

I have a function which makes use of randomness

void fun() {
    random_device rd;
    mt19937 gen(rd());
    uniform_real_distribution<double> dis(0.0, 1.0);
    // ...
}

And, as I suspect, I'll get poor random if it's call repeatedly and both rd and gen are created each time. Is it better to make these variables global/private fields of a class so they are not redeclared multiple times?

Aamir
  • 1,974
  • 1
  • 14
  • 18
sauce
  • 123
  • 6
  • Um, why don't you just do that? – Nicol Bolas Feb 16 '23 at 05:19
  • 2
    You only need to store `mt19937`, since you only use `random_device` once during init. – HolyBlackCat Feb 16 '23 at 05:25
  • 1
    Create the generator once in main, pass a reference to all the code that needs it. (Avoids the use of global variables/dependency injection). You probably also want to do the same for the distribution, that also should not be recreated all the time. You can also place both in a struct as members and pass that around (as a random context) – Pepijn Kramer Feb 16 '23 at 05:49
  • @PepijnKramer Could you explain how "passing a reference to the code that needs it" is different from dependency injection? – wtz Feb 16 '23 at 06:50
  • @wtz it is dependency injection :) I see now my text is a bit off :/ – Pepijn Kramer Feb 16 '23 at 06:59

2 Answers2

1

You can use random_device to generate a seed to initialize mt19937. Since random_device is an expensive operation, no need to call it every time the function is called, and there's no need to save random_device.

mt19937 is not thread safe. If your application is single-threaded, you can save it as a private data member of your class. However, if your application runs in multiple-thread, you'd better make it a thread local variable of the method.

void func() {
  thread_local mt19937(random_device{}());
}
for_stack
  • 21,012
  • 4
  • 35
  • 48
0

A random number generator should be a global object. But there is nothing wrong with burying it in a function for access:

template <typename RealType>
RealType random_real_in_range( RealType min = 0., RealType max = 1. )
{
  thread_local std::mt19937 rng( std::random_device{}() );
  return std::uniform_real_distribution<RealType>( min, max )( rng );
}

The drawback here is that MT really should be “warmed up” by calling .discard( 1000 ) or so...

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39