可播种的 JavaScript 随机数生成器

2022-08-30 01:47:14

JavaScript Math.random() 函数返回一个介于 0 和 1 之间的随机值,根据当前时间自动设定种子(我相信类似于 Java)。但是,我不认为有任何方法可以为它设定自己的种子。

如何制作一个随机数生成器,我可以为其提供自己的种子值,以便我可以让它产生可重复的(伪)随机数序列?


答案 1

一种选择是 http://davidbau.com/seedrandom 这是一个可播种的基于RC4的Math.random()直接替换,具有不错的属性。


答案 2

如果您不需要种子设定功能,只需使用它并围绕它构建帮助程序函数(例如)。Math.random()randRange(start, end)

我不确定您正在使用什么RNG,但最好了解并记录它,以便您了解其特征和局限性。

就像Starkii说的,Mersenne Twister是一个很好的PRNG,但它并不容易实现。如果你想自己做,试着实现一个LCG - 它非常简单,具有不错的随机性质量(不如Mersenne Twister好),你可以使用一些流行的常量。

编辑:考虑这个答案中简短的可种子RNG实现的绝佳选项,包括LCG选项。

function RNG(seed) {
  // LCG using GCC's constants
  this.m = 0x80000000; // 2**31;
  this.a = 1103515245;
  this.c = 12345;

  this.state = seed ? seed : Math.floor(Math.random() * (this.m - 1));
}
RNG.prototype.nextInt = function() {
  this.state = (this.a * this.state + this.c) % this.m;
  return this.state;
}
RNG.prototype.nextFloat = function() {
  // returns in range [0,1]
  return this.nextInt() / (this.m - 1);
}
RNG.prototype.nextRange = function(start, end) {
  // returns in range [start, end): including start, excluding end
  // can't modulu nextInt because of weak randomness in lower bits
  var rangeSize = end - start;
  var randomUnder1 = this.nextInt() / this.m;
  return start + Math.floor(randomUnder1 * rangeSize);
}
RNG.prototype.choice = function(array) {
  return array[this.nextRange(0, array.length)];
}

var rng = new RNG(20);
for (var i = 0; i < 10; i++)
  console.log(rng.nextRange(10, 50));

var digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
for (var i = 0; i < 10; i++)
  console.log(rng.choice(digits));