我正在阅读随机数生成器,并在javascript中调整了xorShift128+算法的实现我了解位移位运算符是如何工作的,以及xor位操作是如何工作的,尽管我仍在学习它们为什么有用,以及它们在xorshift128+中的使用为什么会产生均匀的随机分布。
但更重要的是,我只需要知道它可能使用的数字的范围是什么。它输出整数,我试图得到0到1之间的数字。归纳起来,我看到它的顺序是2**32所以我用它作为除数然而,当我检查一致性时,我注意到数字有偏差它们似乎在0.2=0.7的区域被排斥。
所以我要么搞错了除数的定标,要么搞错了实现,要么对一致性的性质感到困惑任何帮助都将不胜感激。下面是我的代码和分析:
function xorShift128p(seed) {
// seeds
this.x = seed || this.x || 1;
this.y = seed + 1 || this.y || 2;
// swap seeds
let x = this.y;
let y = this.x;
// bit manipulations that are still a little
// obscure to me as to why they work well
y ^= y << 23;
y ^= y >> 17;
y ^= x;
y ^= x >> 26;
// reset seeds
this.x = x;
this.y = y;
// output, with calibration for 0-1 range.
let realResult = x + y;
let myCalibration = realResult / (2**32);
return myCalibration;
}
// produce an array of 100 random numbers using xorShift128p
let rands =
[...new Array(100).keys()]
.map(() => xorShift128p());
// bin the random numbers into units of 0.1
let binCounts =
[...new Array(10).keys()]
.map(key =>
`lead: ${(key / 10).toFixed(1)}, ` +
`count: ${rands.filter(r => r >= key / 10 && r < (key + 1) / 10).length}`
);
// notice the non-uniformity
console.log(binCounts);
最佳答案
在xorshift128+中,x
和y
应该是uint64_t
。这导致此实现与实际的xorshift128+之间存在许多差异:
正确的移位是算术移位,但应该是逻辑移位。我不知道那有多糟,但绝对不同。
最后的加法应该是模的,但这里是一个(浮点)双精度和那太糟糕了。
没有128位的状态这使得prng不那么强大,但在某种程度上是不平凡的检测。
最终的和不是模块化的,使得结果不一致,并且与比例因子假设的范围不同:两个IID数字在[-231]中的和。231-1](使用数字而不是uint64_t
)的结果在[-232..232-2]并且偏向于较小的数量级。这和两个公平的压模辊之和的效果是一样的这可以通过添加>>> 0
来解决,但是代码仍然不会实现xorshift128+。
修复基本问题会有点痛苦,需要对64位整数操作进行仿真。有一些库可以帮你完成这项工作。