Quuxplusone
Quuxplusone

Reputation: 27210

Which of <random>'s random number engines should one actually use in practice? std::mt19937?

Suppose you want to use C++ <random> facilities in a practical program (for some definition of "practical" — the constraints here are kind of part of this question). You've got code roughly like this:

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

My question is, what type should you use for ENGINE?

Obviously there are some competing constraints here.

Weighing all these constraints as best you can, what would you say is the ultimate "best-practice staying-within-the-standard-library" answer? Should I just keep using std::mt19937, or what?

Upvotes: 27

Views: 2596

Answers (2)

Peter O.
Peter O.

Reputation: 32878

C++ Reference lists all the random engines currently provided by C++. However, the selection of engines leaves a lot to be desired (e.g., see my list of high-quality random generators). For instance:

  • default_random_engine is implementation-defined, so it's unknown whether the engine has statistical flaws that the application may care about.
  • linear_congruential_engine implements linear congruential generators. However, they tend to have poor quality unless the modulus is prime and very big (at least 64 bits). Also, they can't admit more seeds than their modulus.
  • minstd_rand0 and minstd_rand admit only about 2^31 seeds. knuth_b wraps a minstd_rand0 and does a Bays–Durham shuffle of it.
  • mt19937 and mt19937_64 could admit a lot more seeds if they were better initialized (e.g., by initializing a std::seed_seq with multiple outputs of random_device, not just one), but they use about 2500 bytes of state.
  • ranlux24 and ranlux48 use about 577 bits of state but they are slow (they work by keeping some and discarding other pseudorandom outputs).

However, C++ also has two engines that wrap another engine to potentially improve its randomness properties:

  • discard_block_engine discards some of the outputs of a given random engine.
  • shuffle_order_engine implements a Bays–Durham shuffle of a given random engine.

For instance, it's possible, say, to have a Bays–Durham shuffle of mt19937, ranlux24, or a custom linear_congruential_engine with shuffle_order_engine. Perhaps the wrapped engine is better quality than the original one. However, it's hard to predict the new engine's statistical quality without testing it.

Thus, pending such tests, it seems that mt19937 is the most practical engine in the C++ standard for now. I am aware, however, of at least one proposal to add another random number engine to future versions of C++ (see C++ paper P2075).

Upvotes: 19

Farbod Ahmadian
Farbod Ahmadian

Reputation: 747

According to C++ Reference, default_random_engine:

Is the library implemention's selection of a generator that provides at least acceptable engine behavior for relatively casual, inexpert, and/or lightweight use.

So for lightweight use you don't need to be worry about anything, seed default_random_engine with Epoch Time (time(0)) and that would be fine enough ;)

Upvotes: 1

Related Questions