4

The C++ standard specifies pretty closely under [rand.util.canonical] just how the template function std::generate_canonical works (though it only presents pseudocode, not C++ code).

Is is the intention of the spec authors that on different platforms where math on the RealType works identically, and for a deterministic URNG that gives the same outputs on the two platforms, that std::generate_canonical gives identical outputs as well?

This is related to similar questions like Is 1.0 a valid output from std::generate_canonical? -- the prose states that 1.0 is excluded, but the algorithm that they give in pseudocode includes it as an output sometimes and for some combinations of RealType and URNG.

This is in contrast to the random number distribution functions, discussed e.g., as C++11 random number distributions are not consistent across platforms -- what alternatives are there?; the standard does '''not''' specify how e.g., the normal distribution is generated, just its properties

I haven't found any DRs where this is discussed, and the wording of the standard is superficially identical in the C++11, C++14 and C++17 draft standards I have easy access to.

Community
  • 1
  • 1
Jeff Epler
  • 502
  • 2
  • 7

1 Answers1

1

The difficulties encountered in the linked question points to the basic problem with consistency: rounding mode. The clear intent of the mathematical definition of generate_canonical in the standard is that the URNG be called several times, each producing a non-overlapping block of entropy to fill the result with; that would be entirely consistent across platforms. The problem is, no indication is given as to what to do with the extra bits below the LSB. Depending on rounding mode and summation order, these can round upwards, spilling into the next block (which is what allows for a 1.0 result).

Now, the precise wording is "the instantiation’s results...are distributed as uniformly as possible as specified below". If the rounding mode is round-to-nearest, an implementation which produces 1.0 is not as uniform as possible (because 1-eps is less likely than 1-2*eps). But it's still "as specified below". So depending on how you parse that sentence, generate_canonical is either fully specified and consistent, or has delegated some extra un-discussed bits to the implementation.

In any case, the fact that certain implementations produce 1.0 makes it quite clear that the current behavior is not cross-platform consistent. If you want that, it seems like the most straightforward approach would be to wrap your URNG in an independent_bits_engine to produce some factor of bits bits, so there's never anything to round.

Sneftel
  • 40,271
  • 12
  • 71
  • 104