For many use cases biased is good enough. The topic of unbiased bounded generation is pretty interesting itself and both lemire and M.E. O'Neill (author of pcg) wrote blog posts and an academic paper comparing different approaches (some using as building block the fixed point trick) https://www.pcg-random.org/posts/bounded-rands.html https://lemire.me/blog/2019/06/06/nearly-divisionless-random... https://arxiv.org/pdf/1805.10941.pdf
Fast Random Integer Generation in an Interval
Daniel Lemire
2018 · arXiv
- HN score
- 0
- Mentions
- 4
- Readers
- 4
- Months
- 3
From the abstract
In simulations, probabilistic algorithms and statistical tests, we often generate random integers in an interval (e.g., [0,s)). For example, random integers in an interval are essential to the Fisher-Yates random shuffle. Consequently, popular languages like Java, Python, C++, Swift and Go include ranged random integer generation functions as part of their runtime libraries. Pseudo-random values are usually generated in words of a fixed number of bits (e.g., 32 bits, 64 bits) using algorithms such as a linear congruential generator. We need functions to convert such random words to random integers in an interval ([0,s)) without introducing statistical biases. The standard functions in programming languages such as Java involve integer divisions. Unfortunately, division instructions are relatively expensive. We review an unbiased function to generate ranged integers from a source of random words that avoids integer divisions with high probability. To establish the practical usefulness of the approach, we show that this algorithm can multiply the speed of unbiased random shuffling on x64 processors. Our proposed approach has been adopted by the Go language for its implementation of the shuffle function.
Metadata: arXiv. Abstracts retain their original authors’ rights.
In the conversation
Original HN comments, with labels from simple text rules. A label describes the whole comment and may miss context or irony. Read the discussion to make up your own mind. About the labels
4 selected excerpts · 4 total mentions
I'm a bit confused. Looking at the original paper (https://arxiv.org/pdf/1805.10941.pdf) this doesn't seem to be a RNG itself but rather a method to efficiently transform the output of a RNG onto an arbitrary interval while maintaining a uniform distribution. (This is at odds with the current title.) See in particular "Algorithm 5" which specifies retrieving a random integer on lines 1 and 7. In section 5, the authors specify that they use a linear congruential generator for their experiments. If my understanding is correct, this is an important distinction because it means you can plug different RNGs into this algorithm depending on your needs (in particular the…
Read the full comment
capabilities of the underlying platform). Related question: For the ultimate in minimal state, would a CBPRNG such as Philox or Threefry (http://www.thesalmons.org/john/random123/papers/random123sc1...) be safe to use here or would the fact that it can be invoked multiple times for a single call (and thus state sequences might end up overlapping between calls) be likely to introduce subtle statistical issues? Slightly off topic - from Lemire's paper: > may not be applicable to specialized processors such as Graphics Processing Units (GPUs) that lack support for the computation of the full multiplication This statement seems to be at odds with the fact that implementations of Philox are provided for both AMD and Nvidia GPUs but Philox relies on efficient mulhi and mullo being available. I didn't bother to look into it further yet though.
After reading the intro of the article, I wanted to see whether I could get the gist of the algorithm just from looking at the first code of it that I come upon. I thus took the first such link from the article (https://arxiv.org/pdf/1805.10941.pdf) while trying to avoid any spoilers. There was no way to unsee the comment at the top of the article, but I don't think it helped much. I did skim the paper to find which of the listed algorithms is the one in question (Algorithm 5), which inevitable primed me a bit (primarily by having the context of the two other rejection sampling algorithms). I also looked at the pseudo-code instead of the real code, so I don't think this…
Read the full comment
is a fair comparison with whatever colleagues of the author had to face, but I had no chance to make it rigorous anyway. The algorithm in question, copied straight from the paper (and ASCII-fied): ALGORITHM 5: An efficient algorithm to generate unbiased random integers in an interval. Require: source of uniformly-distributed random integers in [0, 2^L) Require: target interval [0, s) with s in [0,2^L) x := random integer in [0, 2^L) m := x * s l := m % 2^L if (l < s) then // Application of the rejection method t := (2^L−s) mod s // 2^L mod s = (2^L − s) mod s while (l < t) do x := random integer in [0, 2^L) m := x * s l := m mod 2^L end while end if return m / 2^L Looking only at the part outside the if, I felt the overall idea quite intuitive - it's essentially the equivalent of return floor(s * rand(0, 1)) except you're working with L bit wide fixed point numbers. The remaining question is "when do you have to actually rejection sample". This part is not as obvious. Thinking about the ranges of the variables involved, it becomes clear that m can take values in [0, s * 2^L) that are steps of s apart, and we want to bucket this space into segments of length 2^L. Some of these segments might contain one more of those possible m values than the others. What the `if` therefore has to do is "shorten" the segments so that each one covers the same number of possible values (at least that is my assumption for now - see below). The dead space in between is then where we have to actually do the "rejection" part of rejection sampling. This seems to be the core of the idea - trim the fat between the segments, so that they can all end at a 2^L boundary, thereby eliminating the non-power-of-two division for figuring out which segment m fell in. At this point I'm slightly stumped why the condition is different in the while. We compare with t instead of s, where t < s, but is this required for equiprobability or just for performance reasons? I am left to wonder whether the results for all "not taking the if branch" rolls are equiprobable. If they are, why not rejection-sample on the if directly, completely avoiding any non-trivial remainder calculation in the first place? If they are not equiprobable, that means the results of taking the if branch have to exactly undo the bias of the if-not-taken cases. I assume this is the case, since the goal was to eliminate as many "hard" remainder calculations as possible. On the other hand, it would be very odd for the probabilities involved to work out just right. I mean, if rejection sampling on the if alone has bias, and you only enter the if with a certain probability, and then need to correct that bias while influenced by the conditional probability - that just seems odd. In other words: Does this algorithm have bias? If yes, it's indeed freaky how the part within the if above compensates that. x := random integer in [0, 2^L) m := x * s l := m % 2^L if (l < s) then start over end if return m / 2^L I'll investigate this more deeply (probably by actually reading the full article and paper), but only after some sleep.
It is Julia all the way down. julia> @which randn(1000) randn(dims::Integer...) in Random at ~/Software/Julia/share/julia/stdlib/v1.5/Random/src/normal.jl:210 julia> @edit randn(1000) # Opens the normal.jl file in your editor julia> @run randn(1000) # Starts the debugger in VSCode Digging deeper, at least one of the PRs [1] is based on a 2018 paper [2] [1] https://github.com/JuliaLang/julia/pull/29240 [2] https://arxiv.org/abs/1805.10941
Keep following the thread.
More in Statistics & probabilityMore from the same topics.
Sparks of Artificial General Intelligence: Early experiments with GPT-4
Sébastien Bubeck, Varun Chandrasekaran, Ronen Eldan +11
Artificial intelligence (AI) researchers have been developing and refining large language models (LLMs) that exhibit remarkable capabilities across a variety of domains and tasks, challenging our understanding of learning and cognition.
Dissolving the Fermi Paradox
Anders Sandberg, Eric Drexler, Toby Ord
The Fermi paradox is the conflict between an expectation of a high {\em ex ante} probability of intelligent life elsewhere in the universe and the apparently lifeless universe we in fact observe.
Understanding deep learning requires rethinking generalization
Chiyuan Zhang, Samy Bengio, Moritz Hardt +2
Despite their massive size, successful deep artificial neural networks can exhibit a remarkably small difference between training and test performance.
Talent vs Luck: the role of randomness in success and failure
A. Pluchino. A. E. Biondo, A. Rapisarda
The largely dominant meritocratic paradigm of highly competitive Western cultures is rooted on the belief that success is due mainly, if not exclusively, to personal qualities such as talent, intelligence, skills, efforts or risk taking.