Not-so-unpredictable seed?

jerro a at a.com
Tue Apr 17 21:43:29 PDT 2012


On Wednesday, 18 April 2012 at 03:47:31 UTC, Joseph Rushton
Wakeling wrote:
> Can anyone explain to me why, when I compile & run this code, 
> the two samples seeded with the unpredictableSeed always come 
> out with the same starting value?
>
> //////////////////////////////////////////////////////////////
> import std.random, std.range, std.stdio;
>
> void main()
> {
> 	auto s = randomSample(iota(0, 100), 5);
>
> 	foreach(uint i; s)
> 		writeln(i);
>
> 	writeln();
>
> 	auto s2 = randomSample(iota(0, 100), 5);
>
> 	foreach(uint i; s2)
> 		writeln(i);
>
> 	writeln();
>
> 	auto urng3 = Random(unpredictableSeed);
> 	auto s3 = randomSample(iota(0, 100), 5, urng3);
>
> 	foreach(uint i; s3)
> 		writeln(i);
>
> 	writeln();
>
> 	auto urng4 = Random(unpredictableSeed);
> 	auto s4 = randomSample(iota(0, 100), 5, urng4);
>
> 	foreach(uint i; s4)
> 		writeln(i);
> }
> //////////////////////////////////////////////////////////////
>
> In fact it's not just the unpredictable seed -- no matter what 
> seed I pass, so long as an RNG is passed to the randomSample 
> function, the first entry is always the same.
>
> Note that this is Phobos' randomSample, not my tweaked 
> implementation.
>
> Anyone got any ideas?

When you pass in your own random generator, you use this function:

auto randomSample(R, Random)(R r, size_t n, Random gen)
if (isInputRange!R && hasLength!R && isUniformRNG!Random)
{
       auto ret = RandomSample!(R, Random)(r, n, r.length);
       ret.gen = gen;
       return ret;
}

which calls this constructor:

this(R input, size_t howMany, size_t total)
{
       _input = input;
       _available = total;
       _toSelect = howMany;
       enforce(_toSelect <= _available);
       // we should skip some elements initially so we don't always
       // start with the first
       prime();
}

According to the comment the call to prime() is necessary
so that the result doesn't always start with the same element.
But prime() uses the gen member which is only assigned after the
constructor completes. So at the time when prime() is called the
gen member is in some default state, so the prime() call in the
constructor always does the same thing. The fix would be to
either modify the constructor to take random generator as a
parameter if Random type parameter is not void, or to move the
call to prime() out of constructor and into all the randomSample
functions. In the ones that have a random generator parameter,
the call to prime should come after gen is asigned.


More information about the Digitalmars-d-learn mailing list