Как генерировать случайные числа для создания нестандартного распределения в переполнении стека

Я просмотрел ряд похожих вопросов, но, к сожалению, не смог найти ответ на эту проблему. Я надеюсь, что кто-то может указать мне правильное направление.

Мне нужно придумать функцию PHP, которая будет производить случайное число в пределах заданного диапазона и среднего значения. Диапазон, в моем случае, всегда будет от 1 до 100. Среднее значение может быть любым в пределах диапазона.

Например…

r = f(x)

где…

r = the resulting random number

x = the mean

…запуск этой функции в цикле должен давать случайные значения, где среднее значение полученных значений должно быть очень близко к x. (Чем больше раз мы зациклимся, тем ближе мы окажемся к x)

Запуск функции в цикле, предполагая, что x = 10, должен создать кривую, подобную этой:

     +
+ +
+     +
+             +
+                               +

Где кривая начинается в 1, заглядывает в 10 и заканчивается в 100.

К сожалению, я не очень разбираюсь в статистике. Возможно, кто-то может помочь мне правильно сформулировать эту проблему, чтобы найти решение?

1

Решение

интересный вопрос Я подведу итог:

  1. Нам нужна функция f (x)
  2. f возвращает целое число
  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;

Это дает кривую распределения, которая выглядит следующим образом:
Кривая распределения

0

Другие решения

Я не уверен, понял ли я то, что вы имеете в виду, даже если бы я не понял, это все еще довольно аккуратный фрагмент:

<?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.

0

По вопросам рекламы [email protected]