开发者

Random number but with a bias

开发者 https://www.devze.com 2023-02-25 07:43 出处:网络
How would I go about creating a random number generator which has a bias to be within a range of numbers?

How would I go about creating a random number generator which has a bias to be within a range of numbers? say I have this:

$rnum = rand(0,200);

so $rnum == 3 and next time $rnum == 106 then $rnum == 10 and so on...

But I would rather have a bias range of say 80 - 120 so it would more likely select a number within the bias range than 开发者_高级运维outside of it.

$rnum == 86 and next time $rnum == 112 then $rnum == 93 but still be able to $rnum == 24 and so on...

I thought I might have been able to do this:

if($rnum < $middle_of_bias){
    $rnum++;
}else{
    $rnum--;
}

but didn't really work, as you can see if $rnum == 1 after applying the bias it would only make it 2 not making this method very successful.

Thanks for your help.

Edit: everyones answers were great. I really liked gnur's one and Phil H's I have made my modifications to rmflow's one and it is working how I wanted it to. Thanks to every one that helped!

if (rand(0, 10) > 2)
{
    $rnum = rand($low, $high);
}else{
    $rnum = rand(0, $max);
}


if (rand(0, 10) > 7)
{
    $rnum = rand(80, 120);
}
else
{
    $rnum = rand(0, 200);
}


You probably want to use rand() to get a random number from a larger range in a uniform distribution and then use a function to map that larger range to the smaller range you actually want in a way that produces the distribution you want.


Another possibility to bias your random number:

$rnum = rand(90,110);
$rex1 = 45 - rand(0,90);
$rex2 = 45 - rand(0,90);
$rbias = $rnum + $rex1 + rex2;

This will increase likeliness of numbers around 100, numbers of 0-10 and 190-200 are quite unlikely while numbers between 80-120 are very likely.


create two ranges, one biased, one not.

not biased range: 0, 200
biased range:     80, 120

then pick a likeliness for getting a none biased number, say 20%. that's one 5th, or, 1 out of 5. then generate a random number between 1 and 5, if it comes out as 1, generate a random number from the none biased range. otherwise generate a number from the biased range.

since i started writing, a couple of answers has come in. the answer from rmflow describes my flow, but with a 36% likeliness of getting a none biased number.

good luck! :)


Just add spare capacity to the end of the range and anything above the maximum you shift into the biased range.

$rnum = rand(0,240);
if($rnum > 200) {
    $rnum -= 120; // 201 -> 81
}

This will only double the probability of getting a value in that range. If you want more bias, extend the range further:

$rmax = 200;
$bmin = 80;
$bmax = 120;
$brange = $bmax - $bmin;
$nbias = 4;
$rnum = rand(0,$rmax+($brange*$nbias));
if($rnum > $rmax) {
    $excess -= $rmax; // 201 -> 81
    $remainder  = modulo($rnum,$brange);
    $rnum = $remainder+$bmin;
}


You can do it by defining an array of $item=>$weight:

$biasedArray = array(
  'Blue'   => 50,
  'Yellow' => 30,
  'Pink'   => 10,
  'Green'  => 10,
);

chooseFromBiasedArray($biasArray);

function chooseFromBiasedArray($biasArray) {
  $totalWeight = array_sum($biasedArray);
  $randChoice = rand(1,$totalWeight);

  $currentWeight = 0;
  reset($biasedArray);
  while ($currentWeight < $randChoice) {
    $currentKey = key($biasedArray);

    $currentWeight += $biasedArray[$currentKey];
    if ($currentWeight < $randChoice) {
      next($biasedArray);
    }
  }

  //echo $randChoice . " -> " . current($biasArray);
  return current($biasArray);
}

I wrote it very fast, you can do it much cleaner but the idea will be the same.


The answer by @rmflow would be the way in which I would add a weighted bias to a range. However, I would use the mt_rand function for better randomness.

mt_rand — Generate a random value via the Mersenne Twister Random Number Generator.

It is also purported to be 4x faster (This function produces a better random value, and is 4 times faster than rand()), however, in my experience I see little only a 20% increase in performance.

if (mt_rand(0, 10) > 7)
{
    $rnum = mt_rand(80, 120);
}
else
{
    $rnum = mt_rand(0, 200);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号