I recently stumbled across some other ways that random number generation can go wrong.<p>Suppose you want reproducible results from a seed, along with parallelism. Algorithmic random number generators are usually mutable and generate a <i>sequence</i> of results, limiting parallelism. Rather than a sequence, you want something tree-shaped where you can create an independent random stream for each child task. In higher-level API's, a <i>jump</i> or <i>split</i> operator can be useful.<p>Counter-based random number generators [1] seem pretty useful in that context. An immutable random number generator works like a hash algorithm that maps each input to an output that's difficult to predict. The problem with this is being careful to avoid using the same input twice. You can think of it as allocating random numbers from a very large address space in a reproducible way. How do you partition the address space, predictably, so that every address is used at most once, and nobody runs out?<p>Giving each child a unique ID and generating a stream from that is one way. If the tree is deeper, you'll want a unique seed for each <i>path</i>.<p>When a mutable random number generator is copied to a child task (or maybe just to an iterator), the same random numbers might be generated in two places. Avoiding this is the sort of thing that Rust's borrow checker can prevent - borrowing is okay, but you want to prevent multiple concurrent ownership.<p>[1] <a href="https://en.wikipedia.org/wiki/Counter-based_random_number_generator" rel="nofollow">https://en.wikipedia.org/wiki/Counter-based_random_number_ge...</a>