Настройте функцию для пирамидоподобного распределения - PullRequest
0 голосов
/ 06 ноября 2011

В этот вопрос Мне помогли написать PHP-функцию, которая дает распределение в виде пирамиды:

function getRandomStrength($min, $max) {
    $ln_low = log($min, M_E);
    $ln_high = log($max, M_E);
    $scale = $ln_high-$ln_low;
    $rand = (mt_rand()/mt_getrandmax())*$scale+$ln_low;
    $value = round(pow(M_E, $rand), 1);
    return $value;
}
getRandomStrenth(1.1, 9.9);
// output could be: 1.4 or 8.3 or 9.8 or 7.2 or 2.9 or ...

Когда я запускаю 50 000 итераций и проверяю, как часто появляются числа от 1 до 9, я получаю следующий список:

  • 1 »26%
  • 2 »19%
  • 3 »14%
  • 4 »10%
  • 5 »9%
  • 6 »7%
  • 7 »6%
  • 8 »6%
  • 9 »4%

Это то, что я хотел получить. Но сейчас я бы хотел немного отрегулировать эту функцию. Меньшие значения должны появляться чаще, а большие значения должны появляться реже - так что я получаю такой список:

  • 1 »28%
  • 2 »20%
  • 3 »15%
  • 4 »11%
  • 5 »9%
  • 6 »6%
  • 7 »5%
  • 8 »5%
  • 9 »2%

Как видите, мне просто нужна небольшая модификация. Но что я могу изменить, чтобы моя функция работала так, как ожидалось?

Я попробовал несколько вещей (например, изменив основание логарифма), но это ничего не изменило.

Ответы [ 3 ]

1 голос
/ 08 ноября 2011

Уменьшение $scale вашей функции на небольшую (постоянную) величину, похоже, дает результаты, довольно близкие к тому, что вы ищете. Вы можете добиться более точных результатов, сделав это сокращение $scale функцией случайно сгенерированного числа из mt_rand(), что потребует сохранения (mt_rand()/mt_getrandmax()) в переменной и выполнения некоторой дополнительной математики для $scale.

Вот мои тесты, вы можете запустить его самостоятельно: http://codepad.viper -7.com / ssblbQ

function getRandomStrength($min, $max) 
{
    $ln_low = log($min, M_E);
    $ln_high = log($max, M_E);
    $scale = $ln_high-$ln_low - .05; // Subtract a small constant, vary between .05 and .08
    $rand = (mt_rand()/mt_getrandmax())*$scale+$ln_low;
    $value = round(pow(M_E, $rand), 1);
    return $value;
}

$values = array_fill(1, 9, 0);
for( $i = 0; $i < 50000; $i++) 
{
    $values[ intval( getRandomStrength(1.1, 9.9)) ]++;
}

for( $i = 1; $i <= 9; $i++) 
{
    $values[ $i] /= 500; // / 50000 * 100 to get a percent
}

var_dump( $values);

выход

Прогон № 1 - Константа = 0,5

array(9) {
  [1] => float(26.626) // Should be 28
  [2] => float(19.464) // Should be 20
  [3] => float(13.476) // Should be 15
  [4] => float(10.41) // Should be 11
  [5] => float(8.616) // Should be 9
  [6] => float(7.198) // Should be 6
  [7] => float(6.258) // Should be 5
  [8] => float(5.52) // Should be 5
  [9] => float(2.432) // Should be 2
}

Прогон № 2 - Константа = 0,65

array(9) {
  [1] => float(26.75) // Should be 28
  [2] => float(19.466) // Should be 20
  [3] => float(13.872) // Should be 15
  [4] => float(10.562) // Should be 11
  [5] => float(8.466) // Should be 9
  [6] => float(7.222) // Should be 6
  [7] => float(6.454) // Should be 5
  [8] => float(5.554) // Should be 5
  [9] => float(1.654) // Should be 2
}

Прогон № 3 - Константа = 0,70

array(9) {
  [1] => float(26.848) // Should be 28
  [2] => float(19.476) // Should be 20
  [3] => float(13.808) // Should be 15
  [4] => float(10.764) // Should be 11
  [5] => float(8.67) // Should be 9
  [6] => float(7.148) // Should be 6
  [7] => float(6.264) // Should be 5
  [8] => float(5.576) // Should be 5
  [9] => float(1.446) // Should be 2
}
1 голос
/ 09 ноября 2011

Для n в {0..1} y = (x ^ n) -1, y будет в диапазоне от 0 до x-1.Затем эту кривую легко сопоставить от 0 до некоторого максимального значения путем умножения на диапазон и деления на (x-1).Если вы измените значение x на что-то около единицы, кривая будет почти линейной, а при больших значениях кривая станет больше похожа на хоккейную клюшку, но все равно попадет в тот же диапазон.примерное значение три не будет точно тем, что вы выразили, но вы можете изменить его, чтобы получить искомую кривую распределения.

function getCustomStrength($min, $max, $x_val, $base) {
  $logmax = $base-1;
  $range = $max-$min;
  return (pow($base,$x_val)-1)*($range/($base-1))+$min;
}

function getRandomStrength($min, $max) {
  $rand = mt_rand()/mt_getrandmax();
  $base = 3.0;
  return getCustomStrength($min, $max, $rand, $base);
}

getRandomStrength (1.1, 9.9);

1 голос
/ 08 ноября 2011

Вы можете использовать pow на случайном числе.

$rand = pow( mt_rand()/mt_getrandmax(), 1.2 )*$scale+$ln_low;

Играя со значением экспоненты, вы можете получить меньшее или большее маленькое значение.

...