When dealing with random numbers, one often needs to get a random floating point number between 0 and 1 (not inclusive). Unfortunately, most random generators only deal with integers and/or bytes. Since bytes can be easily converted to integers, question becomes: “How can I convert integer to double number in [0..1)
range?”
Well, assuming you start with 64-bin unsigned integer, you can use something like this:
ulong value = 1234567890; //some random value
byte[] buffer = BitConverter.GetBytes((ulong)0x3FF << 52 | value >> 12);
return BitConverter.ToDouble(buffer, 0) - 1.0;
With that in mind you you can see that 8-byte (64-bit) buffer is filled with double format combined of (almost) all 1's
in exponent and the fraction portion containing random number. If we take that raw buffer and convert it into a double
, we’ll get a number in [1..2)
range. Simply substracting 1.0
will place it in our desired [0..1)
range. It’s as good as distribution of a double can be (i.e. the maximum number of bits - 56 - are used).
This is as good as uniform distribution can get using 64-bit double.
PS: If we apply the same principle to the float
, equivalent code will be something like this (assuming a 32-bit random uint
as input):
uint value = 1234567890; //some random value
byte[] buffer = BitConverter.GetBytes((uint)0x7F << 23 | value >> 9);
return BitConverter.ToSingle(buffer, 0) - 1.0;
PPS: C#'s Random class uses code that’s probably a bit easier to understand:
return value * (1.0 / Int32.MaxValue);
Unfortunately, this will use only 31 bits for distribution (instead of 52 available in double). This will cause statistical anomalies if used later to scale into a large integer range.