我最近发现可以通过谷歌获取随机数,这使我想到了 Math.random()
如何工作。所以我在这里,除非它们使用类似时间的东西,否则我无法理解 Math.random() 是如何实现的,是否有人知道 JavaScript 的 Math.random()
如何工作或等价的方法?
我最近发现可以通过谷歌获取随机数,这使我想到了 Math.random()
如何工作。所以我在这里,除非它们使用类似时间的东西,否则我无法理解 Math.random() 是如何实现的,是否有人知道 JavaScript 的 Math.random()
如何工作或等价的方法?
Math.random()返回一个数值,其为大于或等于0但小于1的正数,使用基于实现的算法或策略以近似均匀分布地选择随机或伪随机值。
以下是V8的实现方式:
uint32_t V8::Random() {
// Random number generator using George Marsaglia's MWC algorithm.
static uint32_t hi = 0;
static uint32_t lo = 0;
// Initialize seed using the system random(). If one of the seeds
// should ever become zero again, or if random() returns zero, we
// avoid getting stuck with zero bits in hi or lo by reinitializing
// them on demand.
if (hi == 0) hi = random();
if (lo == 0) lo = random();
// Mix the bits.
hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
return (hi << 16) + (lo & 0xFFFF);
}
以下是StackOverflow上的相关主题:
参见:There's Math.random(), and then there's Math.random()
直到最近(版本4.9.40之前),V8选择了MWC1616(乘法带进位,组合两个16位部分)作为其伪随机数生成器。它使用64位内部状态,并且大致如下:
uint32_t state0 = 1;
uint32_t state1 = 2;
uint32_t mwc1616() {
state0 = 18030 * (state0 & 0xffff) + (state0 >> 16);
state1 = 30903 * (state1 & 0xffff) + (state1 >> 16);
return state0 << 16 + (state1 & 0xffff);
然后将32位值转换为浮点数,其范围在0和1之间并符合规定。
MWC1616使用的内存较少且计算速度相当快,但不幸的是提供的质量低于标准:
我们已经注意到了这一点,并在了解问题并进行一些研究后,决定基于名为xorshift128+的算法重新实现Math.random。它使用128位内部状态,具有2 ^ 128-1的周期长度,并通过来自TestU01套件的所有测试。
uint64_t state0 = 1;
uint64_t state1 = 2;
uint64_t xorshift128plus() {
uint64_t s1 = state0;
uint64_t s0 = state1;
state0 = s0;
s1 ^= s1 << 23;
s1 ^= s1 >> 17;
s1 ^= s0;
s1 ^= s0 >> 26;
state1 = s1;
return state0 + state1;
}
我们意识到这个问题后的几天内,新的实现已经在V8 4.9.41.0中发布。它将与Chrome 49一起提供。Firefox和Safari也同时采用了xorshift128+。
他们使用"像时间一样的东西"是正确的。伪随机生成器通常使用系统时钟作为种子,因为这是一个好的数字来源,不会始终相同。
一旦用数字播种了随机生成器,它就会生成一系列数字,所有数字都依赖于初始值,但以看起来随机的方式生成。
一个简单的随机生成器(实际上曾经在编程语言中使用)就是使用素数在类似以下算法:
rnd = (rnd * 7919 + 1) & 0xffff;
seed = 1337
36408
22089
7208
63833
14360
11881
41480
13689
6648
您可能需要参考这篇文章:https://hackernoon.com/how-does-javascripts-math-random-generate-random-numbers-ef0de6a20131
顺便提一下,最近我也对这个问题很好奇,然后阅读了NodeJS的源代码。我们可以从Google V8中知道一种可能的实现方式:
随机数的主要入口(MathRandom::RefillCache
函数)如下:
https://github.com/v8/v8/blob/master/src/math-random.cc
如何初始化种子?请参见此处:https://github.com/v8/v8/blob/master/src/base/utils/random-number-generator.cc#L31
关键函数是 (XorShift128
函数):
https://github.com/v8/v8/blob/master/src/base/utils/random-number-generator.h#L119
在这个头文件中,引用了一些论文:
// See Marsaglia: http://www.jstatsoft.org/v08/i14/paper
// And Vigna: http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
<script>
function generateRandom(){ // Generate and return a random number
var num = Math.random();
num = (Math.round((num*10)))%10;
return num;
}
function generateSum(){ // Generate a problem
document.getElementById("ans").focus();
var num1 = generateRandom();
var num2 = generateRandom();
document.getElementById("num1").innerHTML = num1;
document.getElementById("num2").innerHTML = num2;
document.getElementById("pattern1").innerHTML = printPattern(num1);
document.getElementById("pattern2").innerHTML = printPattern(num2);
}
function printPattern(num){ // Generate the star pattern with 'num' number of stars
var pattern = "";
for(i=0; i<num; i++){
if((i+1)%4 == 0){
pattern = pattern+"*<br>";
}
else{
pattern = pattern+"*";
}
}
return pattern;
}
function checkAns(){ // Check the answer and give the response
var num1 = parseInt(document.getElementById("num1").innerHTML);
var num2 = parseInt(document.getElementById("num2").innerHTML);
var enteredAns = parseInt(document.getElementById("ans").value);
if ((num1+num2) == enteredAns){
document.getElementById("patternans").innerHTML = printPattern(enteredAns);
document.getElementById("patternans").innerHTML += "<br>Correct";
}
else{
document.getElementById("patternans").innerHTML += "Wrong";
//remove + mark to remove the error
}
}
function newSum(){
generateSum();
document.getElementById("patternans").innerHTML = "";
document.getElementById("ans").value = "";
}
</script>