> The important property of determinism is that if I set a seed, and then
> make an identical set of calls to the random API, the results will be
> identical every time, so that it's possible to write tests with
> predictable/repeatable results.
Hmmm… I like my stronger determinism definition more than this one:-)
>> I would work around that by deriving another 128 bit generator instead
>> of splitmix 64 bit, but that is overkill.
>
> Not really relevant now, but I'm pretty sure that's impossible to do.
> You might try it as an interesting academic exercise, but I believe
> it's a logical impossibility.
Hmmm… I was simply thinking of seeding a new pg_prng_state from the main
pg_prng_state with some transformation, and then iterate over the second
PRNG, pretty much like I did with splitmix, but with 128 bits so that your
#states argument does not apply, i.e. something like:
/* select in a range with bitmask rejection */
uint64 pg_prng_u64_range(pg_prng_state *state, uint64 range)
{
/* always advance state once */
uint64 next = xoroshiro128ss(state);
uint64 val;
if (range >= 2)
{
uint64 mask = mask_u64(range-1);
val = next & mask;
if (val >= range)
{
/* copy and update current prng state */
pg_prng_state iterator = *state;
iterator.s0 ^= next;
iterator.s1 += UINT64CONST(0x9E3779B97f4A7C15);
/* iterate till val in [0, range) */
while ((val = xoroshiro128ss(&iterator) & mask) >= range)
;
}
}
else
val = 0;
return val;
}
The initial pseudo-random sequence is left to proceed, and a new PRNG is
basically forked for iterating on the mask, if needed.
--
Fabien.