给定随机源(随机位流的生成器),如何在给定范围内生成均匀分布的随机浮点值?
假设我的随机源看起来像:
unsigned int GetRandomBits(char* pBuf, int nLen);
我想实施
double GetRandomVal(double fMin, double fMax);
笔记:
我认为我永远不会说服您确实需要这个,但是写起来很有趣。
#include <stdint.h> #include <cmath> #include <cstdio> FILE* devurandom; bool geometric(int x) { // returns true with probability min(2^-x, 1) if (x <= 0) return true; while (1) { uint8_t r; fread(&r, sizeof r, 1, devurandom); if (x < 8) { return (r & ((1 << x) - 1)) == 0; } else if (r != 0) { return false; } x -= 8; } } double uniform(double a, double b) { // requires IEEE doubles and 0.0 < a < b < inf and a normal // implicitly computes a uniform random real y in [a, b) // and returns the greatest double x such that x <= y union { double f; uint64_t u; } convert; convert.f = a; uint64_t a_bits = convert.u; convert.f = b; uint64_t b_bits = convert.u; uint64_t mask = b_bits - a_bits; mask |= mask >> 1; mask |= mask >> 2; mask |= mask >> 4; mask |= mask >> 8; mask |= mask >> 16; mask |= mask >> 32; int b_exp; frexp(b, &b_exp); while (1) { // sample uniform x_bits in [a_bits, b_bits) uint64_t x_bits; fread(&x_bits, sizeof x_bits, 1, devurandom); x_bits &= mask; x_bits += a_bits; if (x_bits >= b_bits) continue; double x; convert.u = x_bits; x = convert.f; // accept x with probability proportional to 2^x_exp int x_exp; frexp(x, &x_exp); if (geometric(b_exp - x_exp)) return x; } } int main() { devurandom = fopen("/dev/urandom", "r"); for (int i = 0; i < 100000; ++i) { printf("%.17g\n", uniform(1.0 - 1e-15, 1.0 + 1e-15)); } }