Javascript Math.random()不*那*随机......?

时间:2013-07-06 15:54:15

标签: javascript random

我在Javascript中编写了一个显示随机图片的litte函数。返回图片编号的实际行如下所示:

num = Math.floor(Math.random() * RNDGALSIZE);

目前RNDGALSIZE = 72。

但是,我觉得有些图片经常被点击而有些图片很长时间没有出现,所以我编写了一个循环来生成num一些次,并记录num的每个值的次数{{ 1}}出现了。结果如下:

2, 1, 2, 1, 1, 3, 1, 2, 2, 2,    // num = 0 to 9
2, 1, 0, 1, 0, 2, 2, 1, 0, 1,    // num = 10 to 19
1, 2, 0, 1, 0, 0, 1, 1, 2, 1,    // num = 20 to 29
1, 0, 1, 2, 0, 2, 1, 0, 0, 0,    // num = 30 to 39
2, 2, 3, 3, 0, 1, 1, 1, 0, 3,    // num = 40 to 49
2, 1, 2, 1, 3, 2, 3, 2, 1, 1,    // num = 50 to 59
2, 1, 1, 0, 0, 2, 2, 1, 0, 1,    // num = 60 to 69
3, 1                             // num = 70 and 71

正如您所看到的,没有任何值出现超过3次,并且根本没有出现16个值。虽然某些值可能不会发生,但我认为16是很多。我的方法有什么问题吗?

更新

稍后:

4, 4, 3, 6, 5, 5, 3, 3, 2, 2,
2, 2, 2, 2, 3, 5, 3, 1, 4, 2,
4, 3, 0, 1, 1, 0, 1, 4, 4, 4,
2, 0, 5, 3, 0, 4, 2, 0, 2, 1,
2, 3, 4, 3, 2, 4, 3, 2, 0, 5,
4, 4, 4, 2, 3, 4, 4, 4, 5, 1,
2, 2, 4, 2, 0, 3, 4, 2, 2, 1,
4, 1,

正如你所看到的,当3被击中6次时,数组中仍有7个零:/

3 个答案:

答案 0 :(得分:3)

(这是详细说明失败者的回答。)

p[n][k]表示在n次试验后,出现的确切k个不同值(72个)中的概率。很难给出一个精确的闭式表达式,但我们可以使用动态编程很容易地计算它:

var p = [];

p[0] = [];
p[0][0] = 1; // after 0 trials, 100% chance that 0 values have appeared
for(var k = 1; k <= 72; ++k) {
    p[0][k] = 0
}

for(var n = 1; n < 1000; ++n) {
    p[n] = [];
    p[n][0] = 0;
    for(var k = 1; k < n && k <= 72; ++k) {
        p[n][k] = p[n-1][k] * k / 72 + p[n-1][k-1] * (72-k+1) / 72;
    }
    if(n <= 72) {
        p[n][n] = p[n-1][n-1] * (72-n+1) / 72;
    }
    for(var k = n + 1; k <= 72; ++k) {
        p[n][k] = 0;
    }
}

鉴于此,我们可以计算在n次试验后,我们仍然至少有z个“零”的概率(即使没有出现过一次的值):

function probabilityAfterNTrialsOfAtLeastZZeroes(n, z) {
    var ret = 0;
    for(var k = 0; k <= 72 - z; ++k) {
        ret += p[n][k];
    }
    return ret;
}

因此,在91次试验之后,我们仍然有16个或更多“零”的概率是probabilityAfterNTrialsOfAtLeastZZeroes(91, 16),即0.959,即96%。 (实际上,你的很少实际上有点令人惊讶:拥有17个或更多“零”的概率为0.914,因此16个或更少的概率仅为8.6%。)

类似地,在194次试验之后,我们仍有7个或更多“零”的概率是probabilityAfterNTrialsOfAtLeastZZeroes(194, 7),即0.179,即18%。因此,在194次试验之后,你通常会期望少于7个“零”,但如果你多次重复实验,你可能会在五次中几乎每次都有7个或更多的“零”。

我们还可以计算n次试验后预期的“零”数:

function expectedZeroesAfterNTrials(n) {
    var ret = 0;
    for(var z = 0; z <= 72; ++z) {
        ret += z * p[n][72-z];
    }
    return ret;
}

经过91次试验,我们预计expectedZeroesAfterNTrials(91)“零”,即20.164,经过194次试验,我们预计会有4.775“零”。

答案 1 :(得分:1)

你的数字看起来很合理,

Math.pow((71/72),194)*72 // odds of missing a number ^ tries * number of slots
4.774719247726743

由于我们无法得到一个分数,如果我们生活在“确定性随机”世界中,看起来你应该有5而不是7“零”。

相反,您应该选择不替换,然后在0处重新启动池。

编辑可以从jsconsole运行的快速且脏的100测试计数:

function do_test() { x = []; for (var i = 0 ; i < 72 ; i++) x.push(0); for (var j = 0; j < 194; j++) x[Math.floor(Math.random()*72)]++; count = 0; for (var i = 0 ; i < 72 ; i++) if (!x[i]) count++; return count;}


function do_tests(n) { y = []; for (var i = 0; i < n; i++) y.push(do_test()); return y;}

z = do_tests(100)

[5,5,3,6,4,3,2,4,3,3,4,5,2,5,5,3,7,3,3,4,6,4,7, 4,3,7,5,5,3,3,3,4,5,3,3,3,8,3,4,7,8,4,6,3,4,3,4,3, 2,7,6,7,7,5,3,6,1,3,6,5,3,3,5,4,4,5,3,4,6,6,4,3,3, 7,4,11,6,5,9,5,3,6,7,6,9,2,1,7,3,4,4,6,6,7,7,5,2,5, 9,6]

j = 0; for (var i = 0; i < 100; i++) j+=z[i];

473 //所以4.73零时隙是这100次运行的平均值......

答案 2 :(得分:0)

因此,解决方案是跟踪一个数字被击中的频率,以防随机发生器命中一个已经经常被击中的数字,提供一个经常被忽略的数字......

var minhit = Number.MAX_VALUE;
var maxhit = 1;
var index_min = 0;
for (i=0; i<RNDGALSIZE; i++)
{
  if (imgnum[i] < minhit)
  {
    minhit = imgnum[i];
  index_min = i;
  }
  else if (imgnum[i]>maxhit)
  {
    maxhit = imgnum[i];
  }
}
var num = Math.floor(Math.random() * RNDGALSIZE);
if (imgnum[num] == maxhit)
{
  num = index_min;
}
imgnum[num]++;

结果:

2, 2, 1, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
1, 1,