Rules for using <random>

These days, it’s easy to do the right thing.

Don’t do this:

  • Don’t use std::rand(). Ever.
  • Don’t use std::random_shuffle() to permute containers. (Too easy to misuse; can use std::rand() under the hood.)
  • Don’t use any kind of clock for a seed.
  • Don’t use mod (%) to get a random value into a range. It introduces bias.
  • Don’t use std::default_random_engine – it’s probably not the best choice and can vary by implementation.

Do this:

  • Use std::random_device() as a source of entropy. It should be the best randomness your OS can supply.
  • Use std::shuffle() to permute containers. Its interface doesn’t permit misuse like std::random_shuffle().
  • Use std::mt19937 (or std::mt19937_64) as an RNG engine. (Or consider PCG, but that’s not standard – yet.)
  • Seed the engine with as much seed data as it requires for its internal state (using its state_size member), otherwise you’re throwing away entropy. For std::mt19937 this is 624 32-bit values (not just a single 32-bit value). Use std::seed_seq to help with initialization.
  • RNG engines (particularly std::mt19937) can be expensive to initialize (and have large amounts of internal state), so don’t put them on the stack unnecessarily. Consider using thread_local.
  • Use std::uniform_int_distribution (and the other distributions) to get your random number into the required range. The distributions are carefully crafted to be unbiased (why you shouldn’t use %). Note that they work on closed (inclusive) ranges, not half-open ranges – otherwise the max value would be unreachable.

Wrong:

// init RNG
srand(time(NULL));
 
// get random number
int n = rand() % 100;

Right:

// init RNG
std::array<int, std::mt19937::state_size> seed_data;
std::random_device r;
std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 gen(seq);
 
// get random number
std::uniform_int_distribution<int> dis(0,99);
int n = dis(gen);

Edit: Alternatively, Melissa O’Neill has produced randutils which wraps C++11 random number generation in a nice interface, and does the right thing. She knows what she’s talking about: her work on randomness is worth your time.

4 Responses to “Rules for using <random>”

  1. Alan Wolfe Says:

    Hey Ben, is std::rand() the same as the older rand(), and that’s why we should avoid it due to being low quality and offering a low range of output values?

  2. elbeno Says:

    Yes, it’s just the old LCG.

  3. Don’t blink, or you’ll mess up the Mersenne Twister | Backworlds Says:

    […] are unpredictable and evenly distributed. My colleague Ben Deane wrote about modern ways of using randomness in C++ a while back, this is a more thorough […]

  4. Interesting C++ Tutorials | Declan Kelly Says:

    […] Rules for using <random> http://www.elbeno.com/blog/?p=1081 […]

Leave a Reply