When random is not actually random enough

by Austin Seipp

There is a common pattern you see pop up in codebases everywhere that many of us have written: given a set of objects, pick one at random. Every object should have the same chance of being picked. A rather simple and direct solution is to pick a big random number, then clamp that number to the number of choices by modulo:

Set<T> choices = ten_things();
u64 r = random_u64(); // uniform chance over [0..UINT64_MAX]
T chosen = choices[r % 10];

I fondly remember choosing this option several times when I was much younger, especially when writing C — its standard library does not offer anything beyond rand() — and also my other language de jour, Haskell. After all, it is a fairly immediate and intuitive solution when you have such a problem, and almost any codebase or language, no matter how austere or feeble, will have some mechanism to pick a random number.