我正在阅读随机数生成器,并在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+中,xy应该是uint64_t。这导致此实现与实际的xorshift128+之间存在许多差异:
正确的移位是算术移位,但应该是逻辑移位。我不知道那有多糟,但绝对不同。
最后的加法应该是模的,但这里是一个(浮点)双精度和那太糟糕了。
没有128位的状态这使得prng不那么强大,但在某种程度上是不平凡的检测。
最终的和不是模块化的,使得结果不一致,并且与比例因子假设的范围不同:两个IID数字在[-231]中的和。231-1](使用数字而不是uint64_t)的结果在[-232..232-2]并且偏向于较小的数量级。这和两个公平的压模辊之和的效果是一样的这可以通过添加>>> 0来解决,但是代码仍然不会实现xorshift128+。
修复基本问题会有点痛苦,需要对64位整数操作进行仿真。有一些库可以帮你完成这项工作。

07-24 09:32