I\'m trying to generate a random floating point number in between 0 and 1 (whether it\'s on [0,1] or [0,1) shouldn\'t matter for me). Every question online about this seems to i
If you need to generate doubles, the following algorithm could be of use:
CPython generates random numbers using the following algorithm (I changed the function name, typedefs and return values, but algorithm remains the same):
double get_random_double() {
uint32_t a = get_random_uint32_t() >> 5;
uint32_t b = get_random_uint32_t() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
The source of that algorithm is a Mersenne Twister 19937 random number generator by Takuji Nishimura and Makoto Matsumoto. Unfortunately the original link mentioned in the source is not available for download any longer.
The comment on this function in CPython notes the following:
[this function] is the function named genrand_res53 in the original code; generates a random number on [0,1) with 53-bit resolution; note that
9007199254740992 == 2**53
; I assume they're spelling "/2**53
" as multiply-by-reciprocal in the (likely vain) hope that the compiler will optimize the division away at compile-time.67108864
is2**26
. In effect, a contains 27 random bits shifted left 26, andb
fills in the lower 26 bits of the 53-bit numerator.The orginal code credited Isaku Wada for this algorithm, 2002/01/09
Simplifying from that code, if you want to create a float
fast, you should mask the bits of uint32_t
with (1 << FLT_MANT_DIG) - 1
and divide by (1 << FLT_MANT_DIG)
to get the proper [0, 1)
interval:
#include
#include
#include
#include
#include
int main() {
uint32_t r = 0;
float result;
for (int i = 0; i < 20; i++) {
syscall(SYS_getrandom, &r, sizeof(uint32_t), 0);
result = (float)(r & ((1 << FLT_MANT_DIG) - 1)) / (1 << FLT_MANT_DIG);
printf("%f\n", result);
}
return 0;
}
Since it can be assumed that your Linux has a C99 compiler, we can use ldexpf
instead of that division:
#include
result = ldexpf(r & ((1 << FLT_MANT_DIG) - 1), -FLT_MANT_DIG);
To get the closed interval [0, 1]
, you can do the slightly less efficient
result = ldexpf(r % (1 << FLT_MANT_DIG), -FLT_MANT_DIG);
To generate lots of good quality random numbers fast, I'd just use the system call to fetch enough data to seed a PRNG or CPRNG, and proceed from there.