Skip to content

Instantly share code, notes, and snippets.

@milleniumbug
Last active August 17, 2021 23:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milleniumbug/9aa7c49dc70aa4c9bf504f2b7e4e8836 to your computer and use it in GitHub Desktop.
Save milleniumbug/9aa7c49dc70aa4c9bf504f2b7e4e8836 to your computer and use it in GitHub Desktop.
C++11 <random> for babbies

A 3-minute introduction to C++11 <random> for rand() converts:

How to use a pseudo-random number generator:

  1. Include the necessary headers:

If you did this previously...

#include <ctime>
#include <cstdlib>

now do this instead:

#include <ctime>
#include <random>
  1. Initialize (seed) the pseudo-random number generator:

If you did this previously in main():

std::srand(std::time(nullptr));

now do this instead, in global scope:

std::mt19937 generator(std::time(nullptr));

One difference is instead of having a global generator that's used by everything, we have a global generator specific to our application. That's a good thing.

  1. Use a distribution to generate numbers:

If you did this previously:

// generate a random integer from [0, 200)
int x = rand() % 200;
// generate a random integer from [10, 200)
int y = rand() % (200-10) + 10;
// generate a random integer from [0, 5000000)
long long larger_number = (static_cast<long long>(rand()) * (RAND_MAX+1) + rand()) % 5000000;
// generate a random double from [0, 1)
double r = static_cast<double>(rand()) / (RAND_MAX+1);

now do this instead:

// generate a random integer from [0, 200)
int x = std::uniform_int_distribution<int>(0, 199)(generator);
// generate a random integer from [10, 200)
int y = std::uniform_int_distribution<int>(10, 199)(generator);
// generate a random integer from [0, 5000000)
long long larger_number = std::uniform_int_distribution<long long>(0, 4999999)(generator);
// generate a random double from [0, 1)
double r = std::uniform_real_distribution<double>(0.0, 1.0)(generator);

That's it!

More info, disclaimers

Q: Why does this exist?

A: This post exists to prove that "rand() is simpler to use than <random>" argument is not true. The concepts map directly. Now, in my opinion, C++11's <random> has its own problems (see below), but that one is not it. This usage of <random> API C++11 is lacking in some areas, but it's not worse than existing rand() code, and yet, it's still simpler to use, which is what typical existing rand() user cares about the most.

Q: This doesn't seed properly.

A: Yes, it doesn't. Unfortunately, there's no good solution that doesn't involve writing ~50 lines of code, or using an external library. Still, it's no worse than existing rand() code.

Q: Why aren't you using std::random_device()() to seed the generator?

A: You're going to have a lot of fun on MinGW where it will generate the same number every time. I was so annoyed at that I wrote my own wrapper around OS-specific APIs.. But you don't need to use that specific one, you may as well use boost::random_device, which is even better than std::random_device, because it provides .generate(Iter begin, Iter end) that allows to be used as a seed sequence, seeding with as much as the generator wants, by passing the boost::random_device instance directly to the seed operation, and not the result of calling it once.

Q: You're not reusing distributions.

A: This is a potential performance problem (but not for std::uniform_int_distribution and std::uniform_real_distribution). Again, it's not worse than existing rand() code.

Q: A global generator isn't thread safe.

A: Neither is rand().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment