> in the first piece of code, it uses it directly without involving seed_seq.
The footnote hints at her mistake. I don't know whether the footnote was ever correct, but certainly as of C++20 (and even in the C++11 standard I just checked), these two snippets are not equivalent.
The first snippet, as you discovered, does produce 7 (twice) and 13 (once). But it never produces 0, 1, or 42.
The second snippet is the one that never produces 7 or 13. (And yes, I just checked this. It took hours.)
Back to Dimitrij Mijoski:
> Please consider this brute force approach in the future. And please do not reference O’Neill’s article in
> the future, it probably has more false claims. I can only speculate why that article was written. My initial
> guess is that it is meant to be an advertisement of PCG and not real science or engineering. The
> experiment presented there is too slow to actually prove anything. Additionally, the author could
> have used bugged std::random_device.
I think that's a bit of an overreaction on your part.
Heck, I'll email Melissa O'Neill right now with the (IMHO fairly minor) correction.
I admit I'm surprised it took 6 years for anyone to fact-check that code, though. :)
Now, I’ll present my second point.
Both papers and the article do not acknowledge that the seeding of mt19937
with a single integer uses an algorithm that properly fills the whole state with pseudo-random integers. It is not just one integer and all zeroes. The algorithm was
published here
http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/MT2002/emt19937ar.html by the same authors that published the original Mersenne twister. The C++ standard demands this algorithm. It isn’t that terrible to seed
mt19937
with only a single integer as that article and the papers say. It’s OK if you do it.
It's "okay" in the sense of, "Well, I guess it's okay if you do it." It's not OK in the mathematical sense of "it'll give you an actual random sample of the entire possible state space." Does the average programmer care about the latter sense? No, I don't think they do. But the average programmer also has no reason to be attached to MT19937 in the first place. They might prefer a simpler/smaller/faster generator. I personally have written
(49 lines) for the sole purpose of copy-pasting into my own toy projects that need a fast PRNG. If you seed Xoshiro256** with a merely 32-bit seed, then use it to produce 32 bits, it'll never produce 7, or 13 — or any of 3760 other numbers between 1 and 10000. But guess what? My test program to verify that ran in 11 seconds flat. The same thing for MT19937 (which I had to run to produce my comments above) takes literally hours. MT19937 is just awful if what you care about is getting random numbers out of it in a timely fashion. It's the Java of PRNGs.
So what is the proper way to seed this generator? Well, a single integer is actually good for the majority of users, and if you really need wider state space, use
seed_seq
with only few integers.
If you're already paying for heap-allocation (std::seed_seq is basically std::vector with extra steps), then you might as well fill up the seed. I claim there's no good reason to "under-seed" a generator. If you're only going to use 256 bits of seed, then you should just use a generator with 256 bits of state in the first place.
> I personally think that filling the whole state (624 integers) with values from random_device
> is wrong because it wastes the system entropy. If not wrong then slow and pointless.
Sure, but that's a problem with MT19937 asking for too much seed material, not a problem with the core idea of "fully seeding" a generator.
The "novice user" API was proposed (with my strong if irrelevant support) in
P0205R0, and it looks like this:
std::random_device rd;
auto mt = std::mt19937(rd);
Sadly,
P0205R1 seems to have complicated things back into expert territory; it now proposes
std::random_device rd;
auto adaptor = std::seed_adaptor(rd);
auto mt = std::mt19937(adaptor);
I don't immediately understand why this complication was added between R0 and R1, and I'd recommend to Moritz that he re-introduce the original simple approach. Perhaps even provide rvalue overloads taking `SeedGenerator&&`, so that this could work too:
auto mt = std::mt19937(std::random_device()); // awesome, one line
auto xo = xoshiro256ss(std::random_device()); // awesome, one line, but way faster and less entropy-hogging
–Arthur