我正在实施Xorshift生成器和其他人来比较他们在我的系统上的性能 - Windows和Linux。
https://en.wikipedia.org/wiki/Xorshift
我现在正在检查具有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;
}
答案 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的数字才能任何这些数字中的一个。
这基本上意味着我们在这里遇到了一个不明确的工程问题。究竟是近似均匀的接近程度是多少?