随机数但带有偏差

3

我该如何创建一个随机数生成器,使其有偏好地在一定范围内生成数字? 比如我有这样的代码:

$rnum = rand(0,200);

如果下一次 $rnum == 3,那么再下一次 $rnum == 106,然后 $rnum == 10,以此类推...

但我更希望有一个偏差范围,比如80-120,这样更可能选择在偏差范围内的数字而不是外部的数字。

$rnum == 86,下一次是 $rnum == 112,然后是$rnum == 93,但仍然可以是 $rnum == 24,以此类推...

我想我可以这样做:

if($rnum < $middle_of_bias){
    $rnum++;
}else{
    $rnum--;
}

但是实际上并没有起作用,因为如果在应用偏置之后 $rnum == 1,它只会使其变成 2,从而使这种方法不太成功。

谢谢你的帮忙。

编辑:大家的答案都很好。我真的很喜欢 gnur 的答案和 Phil H 的答案。我对 rmflow 的答案进行了修改,现在它按照我想要的方式工作了。 感谢所有帮助我的人!

if (rand(0, 10) > 2)
{
    $rnum = rand($low, $high);
}else{
    $rnum = rand(0, $max);
}

1
你想要偏置多少? - Phil H
7个回答

13
if (rand(0, 10) > 7)
{
    $rnum = rand(80, 120);
}
else
{
    $rnum = rand(0, 200);
}

你为什么选择rand(0,10)>7?这意味着它总是在偏置范围内的次数为11次中的3次。其余8次有20%的机会命中偏置范围(1.6次)。因此,11次中有4.6次在范围内。因此,偏置范围实际上比范围外更少被命中。 - Hugo Delsing
1
@hugo 但是按数字计算,更频繁,因为只有20%的数字会被命中41%的时间。 - gnur
@gnur 正确,与其他任何数字相比,击中它们的机会更大,但我从问题中理解的是他想以高于50%的概率命中偏差范围内的数字。 - Hugo Delsing

1

另一种可能性是偏置您的随机数:

$rnum = rand(90,110);
$rex1 = 45 - rand(0,90);
$rex2 = 45 - rand(0,90);
$rbias = $rnum + $rex1 + rex2;

这将增加100左右的数字的可能性,0-10和190-200之间的数字相当不可能出现,而80-120之间的数字非常可能出现。


1

你可能想要使用 rand() 函数从一个更大的范围内以均匀分布获取随机数,然后使用一个函数将该更大的范围映射到你实际想要的较小范围,并以你所需的分布方式生成结果。


要创建以100为中心的正态分布,您可以使用以下方程式:100 + (200 * rand() - 100) - Tom Anderson
当平均值为100且方差为200时。 - Tom Anderson

0

你可以通过定义一个 $item=>$weight 的数组来实现:

$biasedArray = array(
  'Blue'   => 50,
  'Yellow' => 30,
  'Pink'   => 10,
  'Green'  => 10,
);

chooseFromBiasedArray($biasArray);

function chooseFromBiasedArray($biasArray) {
  $totalWeight = array_sum($biasedArray);
  $randChoice = rand(1,$totalWeight);

  $currentWeight = 0;
  reset($biasedArray);
  while ($currentWeight < $randChoice) {
    $currentKey = key($biasedArray);

    $currentWeight += $biasedArray[$currentKey];
    if ($currentWeight < $randChoice) {
      next($biasedArray);
    }
  }

  //echo $randChoice . " -> " . current($biasArray);
  return current($biasArray);
}

我写得很快,你可以更加规范地完成,但是思路是一样的。


0
只需在范围末尾添加备用容量,任何超过最大值的内容都会被移入偏置范围。
$rnum = rand(0,240);
if($rnum > 200) {
    $rnum -= 120; // 201 -> 81
}

这只会将在该范围内获得值的概率加倍。如果您想要更多的偏差,请进一步扩大范围:

$rmax = 200;
$bmin = 80;
$bmax = 120;
$brange = $bmax - $bmin;
$nbias = 4;
$rnum = rand(0,$rmax+($brange*$nbias));
if($rnum > $rmax) {
    $excess -= $rmax; // 201 -> 81
    $remainder  = modulo($rnum,$brange);
    $rnum = $remainder+$bmin;
}

0
创建两个范围,一个有偏差,一个没有。
not biased range: 0, 200
biased range:     80, 120

然后选择一个不偏倚数字的可能性,比如20%。那就是五分之一,或者说5个中选1个。然后生成一个1到5之间的随机数,如果出现1,就从不偏倚范围内生成一个随机数。否则,就从偏倚范围内生成一个数。

自从我开始写这篇文章以来,已经有几个答案了。rmflow的答案描述了我的流程,但是有36%的可能性得到一个不偏倚的数字。

祝你好运!:)


0

@rmflow的回答是我添加加权偏差到范围的方式。然而,我会使用mt_rand函数来获得更好的随机性。

mt_rand — 通过Mersenne Twister随机数生成器生成随机值。

据说它也比rand()快4倍(此函数产生更好的随机值,比rand()快4倍),但是在我的经验中,我只看到了20%的性能提升。

if (mt_rand(0, 10) > 7)
{
    $rnum = mt_rand(80, 120);
}
else
{
    $rnum = mt_rand(0, 200);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接