如何生成随机数以产生非标准分布 PHP

How to generate random numbers to produce a non-standard distributionin PHP

我搜索了很多类似的问题,但不幸的是我没能找到这个问题的答案。我希望有人能指出我正确的方向。

我需要想出一个 PHP 函数,它会产生一个在设定范围内的随机数和均值。在我的例子中,范围始终是 1 到 100。平均值可以是范围内的任何值。

例如...

r = f(x)

其中...

r = the resulting random number

x = the mean

...运行 这个循环中的函数应该产生随机值,其中结果值的平均值应该非常接近 x。 (循环次数越多越接近x)

运行 循环中的函数,假设 x = 10,应该产生类似于这样的曲线:

     +
    + +
   +     +
  +             +     
+                               +

曲线从 1 开始,从 10 开始,到 100 结束。

不幸的是,我不太精通统计学。也许有人可以帮助我正确地表达这个问题以找到解决方案?

有趣的问题。我总结一下:

  1. 我们需要一个函数 f(x)
  2. f returns 一个整数
  3. 如果我们运行 f 一百万次整数的平均值是x(或者至少非常接近)

我确信有几种方法,但这使用了二项分布:http://en.wikipedia.org/wiki/Binomial_distribution

代码如下:

function f($x){
    $min = 0;
    $max = 100;
    $curve = 1.1;
    $mean = $x;
    $precision = 5; //higher is more precise but slower

    $dist = array();

    $lastval = $precision;
    $belowsize = $mean-$min;
    $abovesize = $max-$mean;
    $belowfactor = pow(pow($curve,50),1/$belowsize);

    $left = 0;
    for($i = $min; $i< $mean; $i++){
        $dist[$i] = round($lastval*$belowfactor);
        $lastval = $lastval*$belowfactor;
        $left += $dist[$i];
    }
    $dist[$mean] = round($lastval*$belowfactor);

    $abovefactor = pow($left,1/$abovesize);
    for($i = $mean+1; $i <= $max; $i++){
        $dist[$i] = round($left-$left/$abovefactor);
        $left = $left/$abovefactor;
    }

    $map = array();
    foreach ($dist as $int => $quantity) {
        for ($x = 0; $x < $quantity; $x++) {
            $map[] = $int;
        }
    }

    shuffle($map);
    return current($map);
}

你可以这样测试(对我有用): $results = array();

for($i = 0;$i<100;$i++){
    $results[] = f(20);
}
$average = array_sum($results) / count($results);
echo $average;

它给出的分布曲线如下所示:

我不确定我是否明白你的意思,即使我没有,这仍然是一个非常简洁的片段:

<?php
    function array_avg($array) {  // Returns the average (mean) of the numbers in an array
        return array_sum($array)/count($array);
    }

    function randomFromMean($x, $min = 1, $max = 100, $leniency = 3) {

        /*
            $x          The number that you want to get close to
            $min        The minimum number in the range
            $max        Self-explanatory
            $leniency   How far off of $x can the result be
        */

        $res = [mt_rand($min,$max)];
        while (true) {
            $res_avg = array_avg($res);

            if ($res_avg >= ($x - $leniency) && $res_avg <= ($x + $leniency)) {
                return $res;
                break;
            }
            else if ($res_avg > $x && $res_avg < $max) {
                array_push($res,mt_rand($min, $x));
            }
            else if ($res_avg > $min && $res_avg < $x) {
                array_push($res, mt_rand($x,$max));
            }
        }
    }

    $res = randomFromMean(22);  // This function returns an array of random numbers that have a mean close to the first param.
?>

如果你然后 var_dump($res),你会得到这样的东西:

array (size=4)
  0 => int 18
  1 => int 54
  2 => int 22
  3 => int 4

编辑:为 $leniency 使用较低的值(如 1 或 2)会导致数组很大,自测试以来,我建议宽大处理 3 左右。