Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate random number in range [M....N] with mean X

Generating a random number in the range [M..N] is easy enough. I however would like to generate a series of random numbers in that range with mean X (M < X < N).

For example, assume the following: M = 10000 N = 1000000 X = 20000 I would like to generate (a large amount of) random numbers such that the entire range [M..N] is covered, but in this case numbers closer to N should become exceedingly more rare. Numbers closer to M should be more common to ensure that the mean converges to X.

The intended target language is PHP, but this is not a language question per se.

like image 482
Ken Adams Avatar asked Nov 09 '22 23:11

Ken Adams


1 Answers

There are many ways to accomplish this, and it would differ very much depending on your demands on precision. The following code uses the 68-95-99.7 rule, based on the normal distribution, with a standard deviation of 15% of the mean.

It does not:

  • ensure exact precision. If you need this you have to calculate the real mean and compensate for the missing amount.
  • created a true normal distributed curve dynamically, as all the three chunks (68-95-99.7) are considered equal within their groups.

It does however give you a start:

<?php

$mean = (int)$_GET['mean']; // The mean you want
$amnt = (int)$_GET['amnt']; // The amount of integers to generate
$sd = $mean * 0.15;
$numbers = array();
for($i=1;$i<$amnt;$i++)
{
    $n = mt_rand(($mean-$sd), ($mean+$sd));
    $r = mt_rand(10,1000)/10; // For decimal counting
    if($r>68)
    {
        if(2==mt_rand(1,2)) // Coin flip, should it add or subtract?
        {
            $n = $n+$sd;
        }
        else
        {
            $n = $n-$sd;
        }
    }
    if($r>95)
    {
        if(2==mt_rand(1,2))
        {
            $n = $n+$sd;
        }
        else
        {
            $n = $n-$sd;
        }
    }
    if($r>99.7)
    {
        if(2==mt_rand(1,2))
        {
            $n = $n+$sd;
        }
        else
        {
            $n = $n-$sd;
        }   
    }
    $numbers[] = $n;
}

arsort($numbers);
print_r($numbers);

// Echo real mean to see how far off you get. Typically within 1%

/*
$sum = 0;

foreach($numbers as $val)
{
    $sum = $sum + $val;
}

 echo $rmean = $sum/$amnt; 
*/

?>

Hope it helps!

like image 124
Fredrik Avatar answered Nov 14 '22 21:11

Fredrik