Morning HN.
Random number generation feels is a somewhat underrepresented topic in the C++ realm. There is a lot of questionable info about it found online and even the standard library is quite behind the times in terms of it's algorithms. It suffers from trying to accommodate sometimes impractical standard requirements and has several ways of getting significantly bad statistical results. This leaves a lot easily achievable performance & quality on the table.
So, being a mathematician who mostly works with stochastic models and wants these models to run fast and well, I embarked on a journey of trying to summarize "what is good and what is bad" and implement the "best stuff there currently is".
Thankfully, the design of C++ <random> is quite flexible and easy to extend. With some cleanup, generalization and compile-time logic all the different algorithms can be wrapped in a generic standard-compatible API.
A result of this work is single-header RNG library which has:
- <random>-compatible generators (PRNGSs) with 3x-6x better performance
- Cryptographically secure generators (CSPRNGs)
- Faster uniform / normal distributions that produce same sequences on every platform
- Quick approximations of some non-linear distributions
- More reliable entropy sources that std::random_device()
- rand()-like API for when we just want random numbers without the boilerplate of proper a <random> setup
Effectively all of this gets us 2x-8x speedups on many workloads while producing even better statistical quality.
Don't think there is anything else like it, so I would like to showcase the result here and hear some opinions on its improvement:
https://github.com/DmitriBogdanov/UTL/blob/master/docs/modul...
For those interested, there is a more detailed rundown of all the quirks of this topic at end of the docs, might prove an interesting read.
One note on API design: I think it's a FANTASTIC idea to have default `rand()` functions available, since very often, you don't really care about the generator and you're just like "just give me a random number, i don't care how". But if you do, you shouldn't have a `seed()` function, because that means you can then never upgrade it without breaking your API contract. It should always be seeded with entropy. This is why glibc's `rand()` is still using an LCG from the late neolithic, they can't ever update it without breaking a gazillion applications and tests. This is the classic example of "Hyrum's law". Doing this also helps with thread-safety: you can just make the seed/state thread-local and then it just works.
Basically, if you want the ability to seed your PRNG, you also need to specify the generator explicitly. The global one is for convenience only, and there should be no ability in the API to seed it.
EDIT: btw, this is a really nice thing about C++, doing this is dead easy: