从xorshift64 *(uint64_t)获取float [0,1]均匀分布

时间:2018-04-06 22:48:42

标签: c++ random x86

我正在实施Xorshift生成器和其他人来比较他们在我的系统上的性能 - Windows和Linux。

https://en.wikipedia.org/wiki/Xorshift

http://xoroshiro.di.unimi.it/

我现在正在检查具有64位状态的生成器,例如来自维基百科的xorshift64star(这里有我的更改来跟踪错误)

double xorshift64star() {
uint64_t x = global_state[0];   /* The state must be seeded with a nonzero value. */
x ^= x >> 12; // a
x ^= x << 25; // b
x ^= x >> 27; // c
global_state[0] = x;
auto u64val =  x * 0x2545F4914F6CDD1D;
double dval = (double)u64val;
return dval;

}

但是,在在线编译器https://www.onlinegdb.com/上运行时,返回的double值始终为0或 3.1148823182455562e-317

我还没有找到一个解决方案来解决如何使这个函数的输出归一化为[0,1]均匀分布,而不会损失太多的精度和熵。

我必须做输出的“核心”转换是什么?

解决!

谢谢@RetiredNinja。 生成器已经对uint64值进行了规范化。然而,只有将其转换为double才不会对该特定编译器起作用。

解决方案是使用http://xoroshiro.di.unimi.it/

中的自定义强制转换
 static inline double to_double(uint64_t x) {
   const union { uint64_t i; double d; } u = {.i = UINT64_C(0x3FF) << 52 | x >> 12 };
   return u.d - 1.0;
}

1 个答案:

答案 0 :(得分:2)

假设您的u64val在0和numeric_limits<uint64_t>::max之间是统一的,那么显而易见的转换是numeric_limits<uint64_t>::max

但这并不是最准确的转换。这里的问题是你最终会产生1.0/numeric_limits<uint64_t>::max的倍数。这显然给许多小值的概率为零。但请考虑一下:0到1e-100 组合之间的所有数字的概率必须是1e-100。这意味着您需要生成大约1e100的数字才能任何这些数字中的一个。

这基本上意味着我们在这里遇到了一个不明确的工程问题。究竟是近似均匀的接近程度是多少?

相关问题