C++ Logo

std-proposals

Advanced search

Re: Comments for P0205 and P2060: Mersenne twister can actually generate 7 and 13

From: Dimitrij Mijoski <dmjpp_at_[hidden]>
Date: Thu, 18 Nov 2021 00:06:04 +0100
Hello,

On Wed, 2021-11-17 at 21:06 +0000, Lénárd Szolnoki via Std-Proposals
wrote:
> Hi,
>
> On Wed, 17 Nov 2021 18:26:41 +0000
> Dimitrij Mijoski via Std-Proposals <std-proposals_at_[hidden]>
> wrote:
>
> > The papers P0205<https://wg21.link/p0205> and
> > P2060<https://wg21.link/p2060> like to improve the code for proper
> > seeding of the standard Mersenne twister. Both papers cite the
> > following article
> > https://www.pcg-random.org/posts/cpp-seeding-surprises.html by
> > Melissa O’Neill. I will start with that article and their claim that
> > the standard Mersenne twister (std::mt19937) can never produce some
> > integers on the first call after seeding. In particular, the numbers
> > 7 are 13 are mentioned. I state that such claim is false with a
> > simple counterexample in code.
> >
> > #include <random>
> > #include <cassert>
> >
> > using namespace std;
> >
> > int main()
> > {
> > auto rnd = mt19937(1080100664);
> > assert(rnd() == 7);
> >
> > rnd = mt19937(736640520);
> > assert(rnd() == 7);
> >
> > rnd = mt19937(1292535796);
> > assert(rnd() == 13);
> > }
>
> Consider the following code:
>
> #include <random>
>
> using gen = std::mt19937;
> using res_t = gen::result_type;
>
> res_t foo(res_t x) {
> gen g(x);
> return g();
> }
>
> `foo` is a pure function. You demonstrated that foo(1080100664) ==
> foo(736640520) == 7 . Since the range and domain are the same finite
> sets, it follows that there must be some number that can never be the
> return value of `foo`.

Yes, you are correct about this. Since 7 is returned at least twice,
some other number isn't returned at all. But...



>
> I don't know how the author of the original article made the mistake,
> but the point still stands: there are some numbers that can never occur
> as the first number from a generator seeded from a single number,
> unless a function similar to `foo` above happens to be a bijection for
> the given generator.

The point is true but is not useful and even dangerous to take it into
consideration. The point of all PRNGs is to call them multiple times.
If I need one and only one random number, I will use std::random_number
directly. It is pointless to use std::random_number to seed a PRNG just
to get a single number from the PRNG. Or, with examples:

// very bad code
std::mt19937 my_rng(std::random_device{}());
if (my_rng() == 7)
    send_detailed_tracking_info_secretly();

// good
if (std::random_device{}() == 7)
    send_detailed_tracking_info_secretly();

I guess this should be added to the documentation.

Best,
Dimitrij.

Received on 2021-11-17 17:06:10