Given a random source (a generator of random bit stream), how do I generate a uniformly distributed random floating-point value in a given range?
Assume that my random source looks something like:
unsigned int GetRandomBits(char* pBuf, int nLen);
And I want to implement
double GetRandomVal(double fMin, double fMax);
Notes:
- I don't want the result precision to be limited (for example only 5 digits).
- Strict uniform distribution is a must
- I'm not asking for a reference to an existing library. I want to know how to implement it from scratch.
- For pseudo-code / code, C++ would be most appreciated
The question is ill-posed. What does uniform distribution over floats even mean?
Taking our cue from discrepancy, one way to operationalize your question is to define that you want the distribution that minimizes the following value:
Where
x
is the random variable you are sampling with yourGetRandomVal(double fMin, double fMax)
function, and means the probability that a randomx
is smaller or equal tot
.And now you can go on and try to evaluate eg a dabbler's answer. (Hint all the answers that fail to use the whole precision and stick to eg 52 bits will fail this minimization criterion.)
However, if you just want to be able to generate all float bit patterns that fall into your specified range with equal possibility, even if that means that eg asking for
GetRandomVal(0,1000)
will create more values between 0 and 1.5 than between 1.5 and 1000, that's easy: any interval of IEEE floating point numbers when interpreted as bit patterns map easily to a very small number of intervals ofunsigned int64
. See eg this question. Generating equally distributed random values ofunsigned int64
in any given interval is easy.This is easy, as long as you have an integer type with as many bits of precision as a
double
. For instance, an IEEE double-precision number has 53 bits of precision, so a 64-bit integer type is enough:I may be misunderstanding the question, but what stops you simply sampling the next n bits from the random bit stream and converting that to a base 10 number number ranged 0 to 2^n - 1.
I don't think I'll ever be convinced that you actually need this, but it was fun to write.
I'm surprised that for question this old, nobody had actual code for the best answer. User515430's answer got it right--you can take advantage of IEEE-754 double format to directly put 52 bits into a double with no math at all. But he didn't give code. So here it is, from my public domain ojrandlib:
NEXT64() gets a 64-bit random number. If you have a more efficient way of getting only 52 bits, use that instead.
To get a random value in [0..1[ you could do something like: