About random
12 Jul 2025
So recently I was implementing some optimisation that requires randomly selecting an item from an array. I looked through the codebase and saw implementations that roughly go like this:
#include <random>
item SelectRandom(std::vector<Item> items) {
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> dist(0, items.size() - 1);
return items[dist(rng)]
}
Yes my first thought was “what’s random_device?”, “what’s mt19937?”, “why do we need uniform distribution?”???
std::random_device
So first, I looked up “random_device C++” here is what I got from our favourite website:
-
std::random_device
is a uniformly-distributed integer random number generator that produces non-deterministic random numbers. -
std::random_device
may be implemented in terms of an implementation-defined psuedo-random number engine if a non-deterministic source (e.g. hardware device) is not a available to the implementation. In this case each std::random_device object may generate the same sequence.
Ok, there’s more words to unpack, what I got from the above was that “we cannot guarantee that std::random_device
will give us “non-deterministic” random numbers because it may be implementation dependent”. Then I looked at the example code that has this comment:
demo only: the performance of many implementations of random_device degrades sharply once the entropy pool is exhausted. For practical use random_device is generally only used to seed a PRNG such as mt19937
Alright, so the conclusion is don’t use std::random_device
to generate random numbers but only use it to seed this thing called “mt19937”.
std::mt19937
Ok, then let’s look this up, and we again land on our favourite website on std::mersenne_twister_engine
and it states:
mersenne_twister_engine
is a random number engine based on Mersenne Twister algorithm. It produces high quality, but not cryptographically secure, unsiged integer random numbers of type UIntType on the interval $[0, 2^w)$
So…there’s this “random number engine”, a quick lookup says it’s something that generates pseudo-random numbers using seed data as entropy source.
Lastly, about the std::uniform_int_distribution
it’s just a class that produces random number based on the uniform random distribution we learn from school.
Here is the summary after all that:
#include <random>
item SelectRandom(std::vector<Item> items) {
std::random_device rd; // creates a random device
std::mt19937 rng(rd()); // use rd() to generate seed value from "entropy", then initialize the engine
std::uniform_int_distribution<int> dist(0, items.size() - 1); // specifies the range and how the random variable are spread
return items[dist(rng)]; // dis(rng) produces the number itself
}
A quick note is that you should actually initialize the random engine once as a class variable rather than creating it everytime you execute the method. This is to prevent the exhaustion of the “entropy” of the system and getting this initial random seed may be slow on some system.
Further readings:
-
How does random device get its “entropy”? this blog post explains it pretty well. Basically the kernel’s random device driver gets random memory bytes, and these randomness is generated by I/O such as mouse movement, keyboard taps, etc.
-
And I happen to chanced upon this great talk by STL