随机数生成器产生有偏见的结果 - 没有明确的原因

时间:2016-12-08 01:33:05

标签: javascript jquery

我最近运行并测试了以下代码以在网页上执行。对于访问我的网页的每个人来说,这段代码应该在他们查看页面之前运行,以便随机地将50%的代码汇集到一个不同的网页中。根据我的理解(和测试)生成的代码(见下文)生成1到10之间的随机数。编译并运行1000次后,我确认生成1,2,3,4,5大约50%的时间和6,7,8,9,10产生50%。因此,我希望根据我的代码,任何拥有1,2,3,4或5的人都符合if语句的标准。

var rando = Math.floor((Math.random() * 10) + 1);
if(rando < 6){
    //execute unrelated jquery code here to modify webpage
}

不幸的是,网页上的执行无法按计划运行。在我的网页的250个唯一访问者中,100个触发了if语句,150个没有触发。虽然这显然是随机机会的结果,但它可能更有可能是我遗漏的一些错误的根源。如上所述,我测试了这段代码,发现它正在生成我希望在堆栈交换上研究这个特定问题的分布,虽然在某些情况下似乎存在随机数生成器的偏差,但我认为我不认为代码遇到了这个问题。任何帮助或见解将不胜感激!

2 个答案:

答案 0 :(得分:1)

简化事物..生成0到1之间的随机数。看看这段代码。命中运行,每次约为50%。

var count = 0;
var numTimes = 10000;

for(var i = 0; i < numTimes; i++)
{
 var rando = Math.floor((Math.random() * 2));
  if(rando === 1){
    count++;
  } 
}

console.log(count/numTimes);

答案 1 :(得分:1)

运行此代码时,您会注意到伪随机值的不同分布。当样本数量较少时,差异可能更明显。 作为Math.random depends of browser's JavaScript engine implementation的输出,它可能会使您的案例的分布不令人满意。

您也可以使用cryptographically random values - 更难实现,但应该为您提供更均匀的分发。 random-js似乎已实施此API。

function test(times) {
  var t = times;
  var a = 0;
  var b = 0;

  while(t --> 0) {
    var rando = Math.floor((Math.random() * 10) + 1);
    if(rando < 6){
        a++;
    }
    else {
      b++;
    }
  } 

  console.log("TEST FOR " + times);
  console.log(a);
  console.log(b);

  console.log("DISTRIBUTION");
  console.log((100 * a/(a + b)).toFixed(2) + "%");
}

test(250);
test(250);
test(250);

test(1024);
test(2048);
test(4096);
test(8192);
test(32768);

在下方,您可以看到crypto.getRandomValues实施。 1000多个样本的分布几乎保证非常接近50%。

function test(times) {
  var t = times;
  var a = 0;
  var b = 0;
  
  var array = new Uint32Array(times / 32);
  window.crypto.getRandomValues(array);

  for (var i = 0; i < array.length; i++) {
    var bitString = array[i].toString(2);
    for (var j = 0; j < 32; j++) {
      if(j < bitString.length && bitString[j] === '1') 
        a++;
      else
        b++;
    }
  }

  console.log("TEST FOR " + times);
  console.log(a);
  console.log(b);
  
  console.log("DISTRIBUTION");
  console.log((100 * a/(a + b)).toFixed(2) + "%");
}

test(256);
test(256);
test(256);

test(1024);
test(2048);
test(4096);
test(8192);
test(32768);