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 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 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.

5 comments

  1. 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. It is worthing to write an input iterator instead of using std::array so that we can avoid extra memory usage.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.