AVX
AVX

Reputation: 329

Picking a random variable from a pdf in javascript

I am having some strange bug, which I cannot grasp where it comes from. I am writing it in js in Google Script environment.

function tester() {
  var pdf = [[0,5],[1,5],[2,40],[3,50]]; // some pdf as a 2d array
  var tuple = [0,0,0,0]; //the resulting pdf from the test
  var rand = 0;

  for (var i = 0; i<100; i++){ //100 times initialize a random variable and then catch the result into the tuple 
    rand = getRandomN(pdf);
    if (rand==0){tuple[0]+=1} //if the outcome==0 then add 1 to the first element of the tuple
       else if (rand==1){tuple[1]+=1}
       else if (rand==2){tuple[2]+=1}
       else if (rand==3){tuple[3]+=1}
  }

  Logger.log(tuple);
}

getRandomN(pdf) returns one outcome according to the pdf

The problem is that the tuple always returns all zeros with 1 at some of the places. It looks like the randomizer works just fine, but looping is gone through only once. Does anyone have a hint?

UPDATE:

function getRandomN(pdf) {
  var result = 0;
  var rand = getRandomInt(0,10000)/100;

  for (var i=1; i<pdf.length; i++){
    pdf[i][1] = pdf[i][1] + pdf[i-1][1];

    }

  if (pdf[pdf.length-1][1] != 100){return undefined}

  //Logger.log(rand);
  for (var i=0; i<pdf.length; i++){
    if (rand<=pdf[i][1]){result=pdf[i][0]; break}

  }
  Logger.log(pdf);
return result;
}

And the standard function from the Mozilla

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

Upvotes: 0

Views: 74

Answers (2)

AVX
AVX

Reputation: 329

I think I know why. Because the scope of pdf is exactly global within the tester() and I am changing it within the getRandomN(pdf), hence, it is increasing all the time, and after the first run it gets updated and I am calculating already from a new pdf, where the last element of the pdf (i.e. cdf) will never be equal to 100. UPDATE: Just if you are interested in the correct code that is working. The part of mapping pdf to cdf is not the most beautiful one. I'd appreciate improvement hints, but it works just fine. Kudos to the contributors for pointing into the right direction.

function getRandomN(pdf) {
  var result = 0;
  var rand = getRandomInt(0,10000)/100;
  var cdf = [];

  //construct the cdf
  for (var i=1; i<pdf.length; i++){
    //handle the first unchanged element
    cdf[0]=[];
    cdf[0][1] = pdf[0][1];
    cdf[0][0] = pdf[0][0];

    cdf[i]=[];
    cdf[i][1] = pdf[i][1] + cdf[i-1][1];
    cdf[i][0] = pdf[i][0];//add all outcomes to the array's first column
    }

  if (cdf[cdf.length-1][1] != 100){return undefined}

  //Logger.log(rand);
  for (var i=0; i<cdf.length; i++){
    if (rand<=cdf[i][1]){result=cdf[i][0]; break}
    }

  //Logger.log(cdf);
return result;
}

Upvotes: 0

Suchit kumar
Suchit kumar

Reputation: 11859

The reason for this is:

  if (pdf[pdf.length-1][1] != 100){return undefined;}

here you are returning undefined if you return 0 or any of rand first index then it will display proper tuple and you can see the loop count.

try running this:

     function tester() {
    	  var pdf = [[0,5],[1,5],[2,40],[3,50]]; // some pdf as a 2d array
    	  var tuple = [0,0,0,0]; //the resulting pdf from the test
    	  var rand = 0;
    
    	  for (var i = 0; i<100; i++){ //100 times initialize a random variable and then catch the result into the tuple 
    	    rand = getRandomN(pdf);
    	    tuple[rand] += 1;
    	  }
    
    	  console.log(tuple);
       document.write(tuple);
    	}
    
     function getRandomN(pdf) {
    	  var result = 0;
    	  var rand = getRandomInt(0,10000)/100;
    	 // console.log(rand);
    	  for (var i=1; i<pdf.length; i++){
    	    pdf[i][1] = pdf[i][1] + pdf[i-1][1];
    
    	    }
    
    	  if (pdf[pdf.length-1][1] != 100){return 0;}//return any of 0,1,2,3 to test your code.
    
    	  for (var i=0; i<pdf.length; i++){
    	    if (rand<=pdf[i][1]){result=pdf[i][0]; break}
    
    	  }
    	//  console.log(pdf);
    	return result;
    	}
    
     function getRandomInt(min, max) {
    	  return Math.floor(Math.random() * (max - min)) + min;
    	}
     tester();

Upvotes: 1

Related Questions