What one Philox round actually does
A conventional generator holds internal state and computes
. Getting the th output means applying times,
and the state you would have to checkpoint is whatever happens to keep in
memory. For std::mt19937 that is 624 words plus an index, in an order the C++
standard never pinned down.
Philox replaces the recurrence with a keyed bijection over a counter:
Constant-time seek, independent substreams per worker, a checkpoint that survives a change of machine: every claim in the paper falls out of that one line, because there is no accumulated state left to disagree about. That leaves one thing to look at. itself.
Ten of those rounds is Philox4x32-10.
The wide multiply is the whole cost. Each round does two multiplications and needs both halves of each product. Scalar code gets that for free, because the hardware produces a 64-bit result whether you asked for one or not. SIMD code does not: the vector instruction sets hand you the low halves or the high halves, never both, so a round costs two instructions where the scalar version costs one. That asymmetry is why naive vectorization disappoints, and working around it is most of what the library does.
Nothing here depends on order. Round reads the output of round and a
key derived from the seed, and nothing else. Ask for the block at counter
and it costs what the block at counter costs: you add
to a 128-bit integer and run the ten rounds. That is why discard is
. It is also why two threads on disjoint counter ranges never
have to talk to each other.