Hi, I wrote this. I'm very surprised it made the front page and I'm a bit embarrassed. People pointing out you can just hash the seed for different "streams" are completely correct, and in video games, people generally don't care about whether two PRNGs are correlated.
I originally found PCG32 because I needed to implement a pure-Swift, cross-platform PRNG for a game jam so my game would run on Linux as well as Mac. For that purpose, it was great.
The problem this seems to be solving, which is that the seeded random number used to generate the level is mixed with the seeded random number used to affect combat.
It just seems trivial to solve though... or maybe I'm getting something wrong... but the solution seems to be to use the seeded random number to generate the level, and then copy the the last output of the random number to seed a new random number controlling combat.
That is, the random number generating the level is immutable with respect to the combat random number?
I also don't understand, i solved (what i think is) the same problem by having a master rng whose output seeded individual rng, one for map generation, one for enemy ai, one for loot, etc...
This depends on what RNG you are using. If the master and the secondary RNGs use the same algorithm without extra internal states (e.g. splitmix or LCG), you will be generating the same stream over and over with small shifts. The end result may not be obvious in your use case, but can be a catastrophe for statistical simulation or the implementation of dropout. PCG32 is a proper solution. Xorshiro provides another solution by using one simple function to advance the internal state by 2^64 iterations.
I was aware of that blog post as well as the counter argument by the xoroshiro author against PCG. I am not studying RNG and can't say which is more correct. To me, I use xoroshiro mainly because PCG64 is complex to implement. My applications do not need extreme randomness so far.
You're right, it's trivial, and I was dramatically overthinking it when I wrote this article. I expect my blog traffic to be about zero, so sometimes things end up half-baked.
The difference is when you're using many PRNG instances in parallel for SIMD, or threaded, or distributed applications, randomly seeded PRNGs might land close to each other in the sequence and end up correlated with each other, but if you ensure each one has a unique stream that's guaranteed not to happen.
If you have a 64 bit seed + 64 bit stream, then it's trivially the same as a 128 bit seed. Just use the top 64 bits of the 128 bit seed as the "stream id".
Partitioning the seed into "seed + ID" only protects you from using the exact same seed for multiple generators, those unique seeds can still begin close to each other in the sequence and overlap their outputs as they step through it. With proper streams every generator has a different sequence so no matter how the seeds are generated, or even if the seeds are the same, they won't overlap each other at any point. For a game it probably doesn't matter, but for more statistically demanding applications it's a nice property to have.
I'm very confused by what you're saying. It seems you're saying that knowing the state of stream 1 teaches me some information about stream 2, specifically that it's guaranteed not to overlap outputs to the first stream. Why is that desirable?
Yes, it works, if you can jump 2^64 iterations quickly. This is how xoroshiro achieves multiple streams. The PCG32 or the xoroshiro method guarantees independent streams. Using high bits in seeds doesn't have the guaranteed behavior. When you have many streams, stream collisions may become an issue.
Right? I'd also be concerned about hash collisions causing one to accidentally generate the same level twice. Seems better to use something like ChaCha; plenty fast and a much large seed space.
Does it need to pass them? A stronger algorithm wouldn't hurt, but it's not being used for cryptography or scientific simulations. It's just for games.
With the goal of having sharable seeds, the smaller space could be considered beneficial. The right tool for the job is more important. Even an 8-bit LFSR is good for certain tasks, like randomizing particle effects for an NES game.
Ah, I missed that there was a data-dependent rotation applied in the output. So it's a lcg plus xorshift plus ddr. Still weaker than I'd like, but if it passes DieHard etc then it passes.
The _advance function in this prng is also way too weak, purely linear with a tiny bit of output mixing. Replacing self.state with the (64-bit) result of the xorshifts would help a lot.
But we have to be careful about claiming that a generator is unreliable. PRNGs are very susceptible to rumor and uncertainty and doubt, because almost nobody understands them
I originally found PCG32 because I needed to implement a pure-Swift, cross-platform PRNG for a game jam so my game would run on Linux as well as Mac. For that purpose, it was great.