Php 5位mt_rand()数字的唯一性如何?

Php 5位mt_rand()数字的唯一性如何?,php,Php,我只是想知道,如果你画一个5位数的数字,一个mt_rand()数字有多独特? 在这个例子中,我试图用这个函数得到500个随机数的列表,其中一些是重复的 要确保循环中绘制的前500个随机数是唯一的,可能需要多少位数字?如果数字是真正的随机数,则有可能重复这些数字。不管有多少个数字,增加更多的数字会使重复的可能性大大降低,但这总是有可能的 最好检查是否存在冲突,然后循环直到没有冲突: $uniques = array(); for($i = 0; $i < 500; $i++) {

我只是想知道,如果你画一个5位数的数字,一个mt_rand()数字有多独特? 在这个例子中,我试图用这个函数得到500个随机数的列表,其中一些是重复的



要确保循环中绘制的前500个随机数是唯一的,可能需要多少位数字?

如果数字是真正的随机数,则有可能重复这些数字。不管有多少个数字,增加更多的数字会使重复的可能性大大降低,但这总是有可能的

最好检查是否存在冲突,然后循环直到没有冲突:

$uniques = array();
for($i = 0; $i < 500; $i++) {
    do {
        $code = mt_rand(10000, 99999);
    } while(in_array($code, $uniques));
    $uniques[] = $code
}
$uniques=array();
对于($i=0;$i<500;$i++){
做{
$code=mt_兰特(10000,99999);
}while(在数组中($code,$uniques));
$uniques[]=$code
}

为什么不使用范围、洗牌和切片

<?php

$uniques = range(10000, 99999);
shuffle($uniques);
$uniques = array_slice($uniques, 0, 500);

print_r($uniques);
此方法成本较低,因为它不会每次搜索数组以查看是否已添加项。这就是说,它确实减少了这种方法的“随机性”。应提供更多关于这些数字将在何处使用的信息。如果这是一个在线赌博网站,这将是最糟糕的!然而,如果这是用于返回一个星座网站的“幸运”数字,我认为这将是好的


此外,此方法可以扩展,将shuffle方法更改为使用mt_rand(其中原始方法仅使用rand)。它也可能使用openssl随机伪字节,但这可能有点过头了。

生日悖论在这里起作用。如果你从10000-99999500次中随机选取一个数字,则很有可能重复

小数字的直观想法

如果你掷硬币两次,大约有一半的时间你会得到一个复制品。如果你掷六面骰子两次,你会得到1/6的时间重复。如果你滚动3次,你将得到重复的4/9(44%)。如果你滚动4次,你会得到至少一个重复的13/18(63.33%)。第五次翻滚,它是49/54(90.7%)。第六次滚动,它是98.5%。第七次滚,它是100%

如果你用20面模具替换六面模具,概率增长会慢一点,但会增长。在3次掷骰后,你有14.5%的复制几率。经过6轮之后,它是69.5%。经过10轮之后,它达到了96.7%,几乎可以确定

数学

让我们定义一个函数
f(num_rolls,num_sides)
,将其推广到任意随机数生成器的任意数量的卷,该随机数生成器从有限的选择集中进行选择。我们将
f(num_rolls,num_sides)
定义为
num_rolls
侧模的
num_rolls
中没有重复的概率

现在,我们可以尝试为此构建一个递归定义。要获得
num\u rolls
唯一编号,您需要首先滚动
num\u rolls-1
唯一编号,然后再滚动一个唯一编号,现在已获得
num\u rolls-1
编号。所以

f(num_rolls, num_sides) = 
  f(num_rolls-1, num_sides) * (num_sides - (num_rolls - 1)) / num_sides
或者

f(num_rolls + 1, num_side) = 
  f(num_rolls, num_sides) * (num_sides - num_rolls) / num_sides
此函数遵循逻辑衰减曲线,从1开始,移动非常缓慢(因为
num\u rolls
非常低,每一步的变化非常小),然后随着
num\u rolls
的增长缓慢加快速度,最后随着函数值越来越接近0而逐渐变小

我创建了一个Google Docs电子表格,其中内置了一个公式函数,可以让您在此处使用:

将此与您的具体问题联系起来


您已经生成了90000个侧边模具500次。上面的电子表格表明,假设一个完全随机的mt_rand,大约75%的时间里,你会期望至少有一对重复。从数学上讲,代码执行的操作是从具有替换项的集合中选择N个元素。换言之,你从9万件物品的袋子里随机抽取一个数字,记下来,然后放回袋子里,再随机抽取另一个数字,重复500次。听起来您希望所有的数字都是不同的,换句话说,您希望从一个集合中选择N个元素而不进行替换。有一些算法可以做到这一点。戴夫·陈(Dave Chen)提出的先洗牌再切片的建议相对简单。Qaribou提出的分别拒绝重复的建议中的Josh是另一种可能性。

你的问题涉及“生日问题”的一种变体,即如果一个班有N名学生,那么至少两名学生有相同生日的概率是多少?看

您可以轻松修改此处显示的公式以回答您的问题。每个学生的生日不是365个概率相等的整数,而是90001(=99999-10000+2)个概率相等的整数,可以在10000到99999之间生成。如果生成500个此类数字,则至少两个数字相同的概率为:

p(500)=1-90001!/(90001^n(90001-500)!)=0.75

因此,在您生成的500个数字中,有75%的几率至少有两个是相同的,或者换句话说,只有25%的几率您可以使用当前使用的方法成功获得500个不同的数字


正如这里的其他人已经建议的那样,我建议检查算法中的重复数字,而不是盲目地生成随机数字,并希望任何一对数字之间都不匹配

随机数不能保证是“唯一的”。有关问题背后的一些数学知识,请参阅。随机!=独一无二。如果你说出这些数字的用途,你可能会得到一个更有用的答案。你的第一段肯定是正确的,但是实施了这个检查,它们不再是均匀分布的随机数了。@hek2mgl,我认为OP不关心均匀分布,他只需要唯一的500 ra
f(num_rolls, num_sides) = 
  f(num_rolls-1, num_sides) * (num_sides - (num_rolls - 1)) / num_sides
f(num_rolls + 1, num_side) = 
  f(num_rolls, num_sides) * (num_sides - num_rolls) / num_sides