我正在实现Xorshift生成器和其他生成器,以比较它们在我的系统(Windows和Linux)上的性能。
https://en.wikipedia.org/wiki/Xorshift
http://xoroshiro.di.unimi.it/
我现在正在检查具有64位状态的生成器,例如Wikipedia中的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/上运行时,返回的双精度值始终为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;
}
最佳答案
假设您的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个数字才能获得这些数字中的任何一个。
这基本上意味着我们这里有一个未明确说明的工程问题。均匀逼近应该到底有多接近?
关于c++ - 从xorshift 64 *(uint64_t)获得浮点数[0,1]均匀分布,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49701952/