在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的数字出现的频率时,我得到以下列表:
这就是我想要的。但现在我想稍微调整一下这个功能。较小的值应该更频繁地出现,而较大的值应该不那么频繁出现 - 这样我得到一个这样的列表:
如您所见,我只需要进行轻微修改。但是我可以改变什么才能使我的函数按预期运行?
我尝试了几件事(例如更改对数的基数),但这并未改变任何内容。
答案 0 :(得分:1)
您可以在随机数上使用pow。
$rand = pow( mt_rand()/mt_getrandmax(), 1.2 )*$scale+$ln_low;
通过使用指数值,您可以获得更少或更多的小值。
答案 1 :(得分:1)
将函数的$scale
减少一小部分(常量)似乎会产生非常接近您正在寻找的结果。通过将$scale
从mt_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);