0

I recently ran and tested the following code to execute on a webpage. For each person who visits my webpage, this code is supposed to run before they view the page in order to randomly funnel 50% of them into seeing a different webpage. The code I produced (see below), based on my understanding (and testing) generates a random number between 1 and 10. After compiling it and running it in 1000 times, I confirmed that 1, 2, 3, 4, 5 are generated approximately 50% of the time and 6, 7, 8, 9, 10 are generated 50%. Thus, I would expect that, based on my code, anyone with a 1, 2, 3, 4, or 5 would meet the criteria of the if statement.

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

Unfortunately, execution on the webpage did not work as planned. Out of 250 unique visitors to my webpage, 100 triggered the if statement, and 150 did not. While this could obviously be the result of random chance, it is probably more likely the source of some error I am missing. As stated above, I tested this code and saw that it was generating the distribution I was expecting I researched this specific issue on stack exchange, and while there appears to be a bias in the random number generator in some instances, I do not think my code runs into that issue. Any help or insight would be greatly appreciated!

  • 2
    Test it 250 times. What are the results? – rassar Dec 08 '16 at 01:35
  • 2
    Some folks, browsers, bots may have JavaScript disabled so the default would not be to do the if. That could account for some of the skew/bias. – Muskie Dec 08 '16 at 01:54

2 Answers2

1

Simplify things.. generate a random number between 0 and 1. Check out this code. Hit run and it will be about 50% each time.

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);
Jordan Soltman
  • 3,795
  • 17
  • 31
1

As you run this code you will notice varying distribution of pseudo random values. The difference might be more noticeable when sample count is low. As the output of Math.random depends of browser's JavaScript engine implementation it might yield not satisfying distribution for your case.

You might also use cryptographically random values - harder to implement but should give you more uniform distribution. random-js seems to implement this 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);

Down below you can see crypto.getRandomValues implementation. Distribution for 1000+ samples is almost guaranteed to be very close to 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);
Community
  • 1
  • 1
Przemysław Zalewski
  • 3,836
  • 1
  • 23
  • 23