Yes:
s3 = (s3 << 45) | (s3 >> 19);
rngState[0] = s0;
rngState[1] = s1;
rngState[2] = s2;
rngState[3] = s3;
return res;
}
/*
The jl_rng_split function forks a task's RNG state in a way that is essentially
guaranteed to avoid collisions between the RNG streams of all tasks. The main
RNG is the xoshiro256++ RNG whose state is stored in rngState[0..3]. There is
also a small internal RNG used for task forking stored in rngState[4]. This
state is used to iterate a linear congruential generator (LCG), which is then
put through four different variations of the strongest PCG output function,
referred to as PCG-RXS-M-XS-64 [1]. This output function is invertible: it maps
a 64-bit state to 64-bit output. This is one of the reasons it's not recommended
for general purpose RNGs unless space is at an absolute premium, but in our
usage invertibility is actually a benefit (as is explained below) and adding as
little additional memory overhead to each task object as possible is preferred.
Although I figured out a way to majorly simplify the splitmix algorithm so that it doesn’t require arithmetic in a prime modulus, all explained in that massive comment.
5 Likes