Different probability for ranges of random numbers

微笑、不失礼 提交于 2019-11-30 15:25:54

Hmm, working on your original I had a pretty simple algorithm to generate ranges in an array in the appropriate proportion, then randomly select a range and generate a random number within that range. No doubt it can be optimised if necessary, but it works for me.

It looks like a lot of code, but 3/4 of it is comments, test data and function, the actual randomRange function is only 17 lines of code.

<script type="text/javascript">

function randomRange(dataArray) {

  // Helper function
  function getRandomInRange(s, f) {
    return (Math.random() * (f-s+1) | 0) + s
  }

  // Generate new data array based on probability
  var i, j = dataArray.length;
  var oArray = [];
  var o;
  while (j--) {
    o = dataArray[j];

    // Make sure probability is an integer
    for (i=0, iLen=o.probability|0; i<iLen; i++) {  
      oArray.push([o.rangeStart, o.rangeEnd]);
    }
  }

  // Randomly select a range from new data array and
  // generate a random number in that range
  var oEnd = oArray.length;
  var range = oArray[getRandomInRange(0, oArray.length - 1)]; 
  return getRandomInRange(range[0], range[1]);
}

// Test data set. Probability just has to be
// representative, so 50/50 === 1/1
var dataArray = [
  {
    rangeStart: 0, 
    rangeEnd  : 20,
    probability: 1
  },
  {
    rangeStart: 21, 
    rangeEnd  : 400,
    probability: 1
  }
];

// Test function to show range and number is randomly
// selected for given probability
function testIt() {
  var el0 = document.getElementById('div0');
  var el1 = document.getElementById('div1');
  function run() {
    var n = randomRange(dataArray);
    if (n <= 20) {
      el0.innerHTML += '*';
    } else {
      el1.innerHTML += '*';
    }
  }
  setInterval(run, 500);
}


</script>

<button onclick="testIt();">Generate random number</button>

<div>Numbers 0 - 20</div>
<div id="div0"></div>
<div>Numbers 21 - 400</div>
<div id="div1"></div>

It sounds to me like what you're looking for is a way to generate numbers on a normal (or Gaussian) distribution (take a look at the Wikipedia page if you don't know what that means).

The Box-Muller transformation can be used to generate pairs of normally distributed numbers.

Here is a c++ implementation of the polar form of the Box-Muller transformation that shouldn't be hard to translate to javascript.

// Return a real number from a normal (Gaussian) distribution with given
// mean and standard deviation by polar form of Box-Muller transformation
double x, y, r;
do
{
    x = 2.0 * rand() - 1.0;
    y = 2.0 * rand() - 1.0;
    r = x * x + y * y;
}
while ( r >= 1.0 || r == 0.0 );
double s = sqrt( -2.0 * log(r) / r );
return mean + x * s * stddev;

Where mean is the mean of the normal distribution and stddev is the Standard Deviation of the distribution. This code is from a MersesenneTwister C++ class that I've been using recently that you can find on Rick Wagner's page. You can find some more useful information about the Box-Muller transformation on this page.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!