JavaScript Math.random()
函数返回0到1之间的随机值,根据当前时间自动播种(类似于Java我相信).但是,我认为没有办法为你设置自己的种子.
如何创建一个随机数生成器,我可以提供自己的种子值,以便我可以生成一个可重复的(伪)随机数序列?
一个选项是http://davidbau.com/seedrandom,这是一个基于RC4的可种子Math.random()替换,具有很好的属性.
如果您不需要播种功能,只需Math.random()
在其周围使用并构建辅助函数(例如randRange(start, end)
).
我不确定您使用的RNG是什么,但最好知道并记录它,以便您了解它的特性和局限性.
就像Starkii所说,Mersenne Twister是一个很好的PRNG,但实施起来并不容易.如果你想自己尝试实现一个LCG - 它很容易,具有良好的随机性质(不如Mersenne Twister),你可以使用一些流行的常量.
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));
如果您希望能够指定种子,则只需要将调用替换为getSeconds()
和getMinutes()
.你可以传入一个int并使用mod 60的一半作为秒值,另一半使用modulo 60给你另一部分.
话虽这么说,这种方法看起来像垃圾.做适当的随机数生成非常困难.这个问题的一个明显问题是随机数种子基于秒和分钟.要猜测种子并重新创建随机数流,只需要尝试3600种不同的秒和分钟组合.这也意味着只有3600种不同的种子.这是可以纠正的,但我从一开始就怀疑这个RNG.
如果您想使用更好的RNG,请尝试Mersenne Twister.它是经过良好测试且相当强大的RNG,具有巨大的轨道和出色的性能.
编辑:我真的应该是正确的,并将其称为伪随机数生成器或PRNG.
"任何使用算术方法产生随机数的人都处于犯罪状态."
--- John von Neumann
我使用Mersenne Twister的JavaScript端口:https: //gist.github.com/300494 它允许您手动设置种子.另外,正如其他答案中所提到的,Mersenne Twister是一个非常好的PRNG.
您列出的代码类似于Lehmer RNG.如果是这种情况,则2147483647
是最大的32位有符号整数,2147483647
是最大的32位素数,并且48271
是用于生成数字的全周期乘数.
如果这是真的,您可以修改RandomNumberGenerator
以接受额外的参数seed
,然后设置this.seed
为seed
; 但是你必须小心确保种子会导致随机数的良好分布(Lehmer可能会像这样奇怪) - 但是大多数种子都会很好.
以下是可以提供自定义种子的PRNG.调用SeedRandom
将返回随机生成器函数.SeedRandom
可以使用无参数调用,以便使用当前时间为返回的随机函数设定种子,或者可以使用1或2个非负片段作为参数调用它,以便使用这些整数对其进行种子处理.由于浮点精度,只有1个值的播种只允许发生器启动到2 ^ 53个不同状态之一.
返回的随机生成器函数采用1个整数参数命名limit
,限制必须在1到4294965886范围内,该函数将返回0到limit-1范围内的数字.
function SeedRandom(state1,state2){ var mod1=4294967087 var mul1=65539 var mod2=4294965887 var mul2=65537 if(typeof state1!="number"){ state1=+new Date() } if(typeof state2!="number"){ state2=state1 } state1=state1%(mod1-1)+1 state2=state2%(mod2-1)+1 function random(limit){ state1=(state1*mul1)%mod1 state2=(state2*mul2)%mod2 if(state1使用示例:
var generator1=SeedRandom() //Seed with current time var randomVariable=generator1(7) //Generate one of the numbers [0,1,2,3,4,5,6] var generator2=SeedRandom(42) //Seed with a specific seed var fixedVariable=generator2(7) //First value of this generator will always be //1 because of the specific seed.该生成器具有以下属性:
它有大约2 ^ 64种不同的可能内部状态.
它的周期约为2 ^ 63,比任何人在JavaScript程序中实际需要的都要多.
由于
mod
值是素数,因此无论选择的限制如何,输出中都没有简单的模式.这与一些简单的PRNG不同,后者表现出一些相当系统的模式.它会丢弃一些结果,以便无论极限如何都能获得完美的分布.
它相对较慢,在我的机器上每秒运行大约10000万次.
为什么这会产生一种模式?`for(var i = 0; i <400; i ++){console.log("input:("+ i*245 +","+ i*553 +")| output:"+ SeedRandom(i*245, i*553)(20)); }`