调整金字塔状分布的功能

时间:2011-11-05 21:36:07

标签: php function random numbers distribution

this question中,我帮助编写了一个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 个答案:

答案 0 :(得分:1)

您可以在随机数上使用pow。

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

通过使用指数值,您可以获得更少或更多的小值。

答案 1 :(得分:1)

将函数的$scale减少一小部分(常量)似乎会产生非常接近您正在寻找的结果。通过将$scalemt_rand()中随机生成的数字的函数减少(mt_rand()/mt_getrandmax()),可以获得更准确的结果,这需要将$scale保存到变量并在{{{{}}上执行一些额外的数学运算。 1}}。

以下是我的测试,您可以自行运行: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
}

答案 2 :(得分:1)

对于{0..1}中的n,y =(x ^ n)-1,y的范围为0到x-1。然后,通过乘以范围并除以(x-1),可以容易地将该曲线从0映射到某个最大值。如果将值x更改为接近1的值,则曲线将近似为线性,并且在较大值时,曲线变得更像曲棍球棒,但仍然会落在相同的范围内。

我的初始样本值3不会精确地表达您所表达的,但您可以调整它以获得您正在寻找的分布曲线。

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);