是否有可能在JavaScript中播种随机数生成器(Math.random) ?


当前回答

如今,许多需要Javascript中可种子随机数生成器的人都在使用David Bau的seedrandom模块。

其他回答

Antti Sykäri的算法很好,很短。我最初做了一个变种来取代JavaScript的Math。当你调用Math.seed(s)时是随机的,但随后Jason评论说返回函数会更好:

Math.seed = function(s) {
    return function() {
        s = Math.sin(s) * 10000; return s - Math.floor(s);
    };
};

// usage:
var random1 = Math.seed(42);
var random2 = Math.seed(random1());
Math.random = Math.seed(random2());

这为您提供了JavaScript没有的另一个功能:多个独立的随机生成器。如果您希望同时运行多个可重复的模拟,这一点尤其重要。

编写自己的伪随机生成器非常简单。

戴夫·斯科塞斯的建议是有用的,但正如其他人指出的那样,它并不是完全均匀分布的。

然而,这并不是因为sin的整数参数。这只是因为sin的范围,恰好是一个圆的一维投影。如果取圆的角度,它就会是均匀的。

所以用arg(exp(i * x)) / (2 * PI)代替sin(x)

如果你不喜欢线性顺序,可以把它和异或混合一下。实际因素也没有那么重要。

要生成n个伪随机数,可以使用以下代码:

function psora(k, n) {
  var r = Math.PI * (k ^ n)
  return r - Math.floor(r)
}
n = 42; for(k = 0; k < n; k++) console.log(psora(k, n))

还请注意,当需要真实熵时,不能使用伪随机序列。

数学。不是随机的,但是ran库解决了这个问题。它几乎拥有你能想象到的所有分布,并支持种子随机数生成。例子:

ran.core.seed(0)
myDist = new ran.Dist.Uniform(0, 1)
samples = myDist.sample(1000)

对于0到100之间的数。

Number.parseInt(Math.floor(Math.random() * 100))

不可能在Math中植入种子。随机函数,但是用Javascript实现一个高质量的RNG是可能的,只需很少的代码。

Javascript数字是64位浮点精度,可以表示小于2^53的所有正整数。这给我们的算法带来了一个硬限制,但在这些限制内,您仍然可以为高质量的Lehmer / LCG随机数生成器选择参数。

function RNG(seed) {
    var m = 2**35 - 31
    var a = 185852
    var s = seed % m
    return function () {
        return (s = s * a % m) / m
    }
}

Math.random = RNG(Date.now())

如果你想要更高质量的随机数,代价是速度慢10倍,你可以使用BigInt进行算术,并选择m刚好适合双精度的参数。

function RNG(seed) {
    var m_as_number = 2**53 - 111
    var m = 2n**53n - 111n
    var a = 5667072534355537n
    var s = BigInt(seed) % m
    return function () {
        return Number(s = s * a % m) / m_as_number
    }
}

参见Pierre l’ecuyer的这篇论文,了解上述实现中使用的参数: https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf

无论你做什么,避免使用Math.sin的所有其他答案!