MCG initialisation
I notice that the C++ code forces two bits high:
engine(itype state = itype(0xcafef00dd15ea5e5ULL))
: state_(this->is_mcg ? state|state_type(3U)
: bump(state + this->increment()))
{
// Nothing else to do.
}
while the C code only forces one bit high:
inline void pcg_mcg_128_srandom_r(struct pcg_state_128* rng, pcg128_t initstate)
{
rng->state = initstate | 1u;
}
Is there a reason these two are not equivalent?
I also notice that this variant is missing from the C++ test suite (although since it is only ever initialised to 42 in the suite, no one would notice this difference).
One issue that came up is a difference in the construction of MCGs (e.g.
pcg64_fast):* `pcg-c` uses `initstate | 1u` to seed an MCG [src](https://github.com/imneme/pcg-c/blob/master/include/pcg_variants.h#L812) * `pcg-cpp` uses `state | 3u` to seed an MCG [src](https://github.com/imneme/pcg-cpp/blob/master/include/pcg_random.hpp#L484)We decided to mirror the C version src, but standardisation or documentation by @imneme would be nice.
As this issue comes up from time to time, I'm going to risk a bit of futility by reviving an old topic. Apologies to @dhardy if he already knows the things I've written here.
The reason that PCG masks the two low-order bits of MCG state is because they never change. Setting them to a prescribed value makes them predictable.
You should test this yourself by writing a program that gets access to the internal state. The trick is to use operator<< to write the state out to a std::stringstream, and then read it back into an appropriately sized unsigned integer. (Otherwise, you can just make state_ public for a quick test.)
When I did this, I learned that the two low-order bits never change. During seeding, it does not matter what mask you use. Whatever values you set for the two LSBs, you'll be stuck with them. Random number generation does not modify them.
In the C++ implementation, they are both set to 1 (i.e., state | 3) because that version includes member function wrapped(), a function that returns true when a PCG engine has cycled through a full period. For an MCG, function wrapped() returns state_ == 3.
I don't know much about the C implementation, but I believe it does not have a wrapped() function. If you examine the code closely, however, you may discover some sort of similar test that relies on the initialization given by initstate | 1u .
So, what about the sequences generated by PCG? Given identical seeds, and four different engines that set the bits to 00, 01, 10, and 11, would the four engines produce identical output? The obvious answer is that depends how those bits are used by the permutation function. If they are used in any way at all, then the sequences would probably be different.
Does that affect the quality of the generated numbers? Hopefully not, but I am not qualified to answer the question. Presumably, Melissa O'Neill has chosen permutations where the answer is no.
Let us know if you find anything more...