Ranges and random numbers -- again

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Jun 18 07:31:18 PDT 2013


On Tue, Jun 18, 2013 at 11:27:03AM +0100, Joseph Rushton Wakeling wrote:
> On 06/18/2013 11:00 AM, monarch_dodra wrote:
> > The last issue is input vs forward. IMO, PRNG's should be input by
> > *default*, and forward (when possible) on demand.

+1.


[...]
> > In the above example with dual call to "array", one can *hope* to
> > have two different ranges... but there is nothing preventing array
> > from calling "save" just to troll the user. fill does (used to) do
> > it :D
> > 
> > I was also able to implement this pretty easily: Just give the
> > saveable ranges the "dup" primitive. Users of the PRNG can then
> > explicitly dup if they want to very safely and explicitly. If they
> > really want a ForwardPRNG, then a simple adaptor that adds save in
> > terms of dup is provided.

+1. We should follow D's dictum of being safe/correct by default, but
allow the user to get under the hood if they need to. Copying a PRNG
state is a potentially unsafe (in the probabilistic sense) operation, so
it should be made explicit -- call .dup if the user really wants a copy
of the PRNG sequence, pass by reference otherwise.


> I think in principle one could have a .forward() method/property that
> would return a forward-range wrapper of the range in question.
> 
> So, with this concept, one would expect,
> 
>     auto t1 = rndGen.take(5);
>     writeln(t1);
> 
>     auto t2 = rndGen.take(5);
>     writeln(t2);
> 
> ... to produce _different_ sequences (as rndGen would be merely an input range,
> and not .save-able), whereas
> 
>     auto gen = rndGen.forward;
> 
>     auto t1 = gen.take(5);
>     writeln(t1);
> 
>     auto t2 = gen.take(5);
>     writeln(t2);
> 
> .... would produce identical sequences as before.
[...]

Actually, take doesn't (and shouldn't!) call .save, so both cases should
return different sequences. The cause of the original problem was that
RNGs are being passed by value, so you're actually working on copies of
the PRNG state.

Also, the above code is obscure; someone reading the code may have
missed the call to .forward and thus misunderstand the intent of the
code. I much rather provide .dup and force the user to write this:

	auto gen = rndGen;
	auto t1 = gen.dup.take(5); // Explicit call to .dup
	auto t2 = gen.take(5);

This states up-front that we're expecting two identical sequences from
the (P)RNG, so someone reading the code wouldn't be misled to think two
different sequences are being generated. Self-documenting code is always
better than code whose semantics rely on obscure contextual information
that is easily missed.


T

-- 
Debian GNU/Linux: Cray on your desktop.


More information about the Digitalmars-d mailing list