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:

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:

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: