PHP - rand(1,1000)=1000和rand(1,1000)= rand(1,1000)一样可能吗?

7

这是PHP如何生成随机数的实现吗?

假设我想计算一个“是”或“否”的结果。每次我有一个特定的概率百分比(例如:0.05% 作为本例),

我会执行以下操作:

$possibilities = 100 / $probabilityPercentage; //$possibilities = 2000
$yes = rand(1,$possibilities);

$yesCheck = $possiblities;            //OPTION 1
$yesCheck = rand(1,$possibilities);   //OPTION 2


($yesCheck == $yes) ? return true : return false;

它们两个选项会得到相同的结果吗?
7个回答

11

让数据说明问题。

代码

vinko@parrot:~$ more rand.php
<?php

$randrandsum = 0;
$randconstsum = 0;
$count = 20;
for ($j = 0; $j < $count; $j++) {
        $randrand = 0;
        $randconst = 0;
        for ($i = 0; $i < 10000000; $i++ ){
                $a = rand(1,1000);
                $b = rand(1,1000);
                if ($a == $b) $randrand++;
        }
        for ($i = 0; $i < 10000000; $i++ ){
                $a = rand(1,1000);
                $c = 1000;
                if ($c == $a) $randconst++;
        }
        $randrandsum += $randrand;
        $randconstsum += $randconst;
        print ($j+1)." RAND-RAND: $randrand RAND-CONST: $randconst\n";
}
print "AVG RAND-RAND: ".($randrandsum/$count);
print " AVG RAND-CONST: ".($randconstsum/$count)."\n";
?>

测试运行

vinko@parrot:~$ php rand.php
1 RAND-RAND: 10043 RAND-CONST: 10018
2 RAND-RAND: 9940 RAND-CONST: 10132
3 RAND-RAND: 9879 RAND-CONST: 10042
4 RAND-RAND: 9878 RAND-CONST: 9965
5 RAND-RAND: 10226 RAND-CONST: 9867
6 RAND-RAND: 9866 RAND-CONST: 9992
7 RAND-RAND: 10069 RAND-CONST: 9953
8 RAND-RAND: 9967 RAND-CONST: 9862
9 RAND-RAND: 10009 RAND-CONST: 10060
10 RAND-RAND: 9809 RAND-CONST: 9985
11 RAND-RAND: 9939 RAND-CONST: 10057
12 RAND-RAND: 9945 RAND-CONST: 10013
13 RAND-RAND: 10090 RAND-CONST: 9936
14 RAND-RAND: 10000 RAND-CONST: 9867
15 RAND-RAND: 10055 RAND-CONST: 10088
16 RAND-RAND: 10129 RAND-CONST: 9875
17 RAND-RAND: 9846 RAND-CONST: 10056
18 RAND-RAND: 9961 RAND-CONST: 9930
19 RAND-RAND: 10063 RAND-CONST: 10001
20 RAND-RAND: 10047 RAND-CONST: 10037
AVG RAND-RAND: 9988.05 AVG RAND-CONST: 9986.8

根据以上结果,我认为在实际情况下,这两个选项是相当的,都会得到预期的1/1000的结果。


2
+1,虽然我必须用http://www.dilbert.com/dyn/str_strip/000000000/00000000/0000000/000000/00000/2000/300/2318/2318.strip.gif来回答你的“让数据说话”。 - balpha
2
这个测试方法实际上是不正确的,因为它在每次迭代中总是调用rand()两次。更准确的测试应该运行一个循环测试rand(1,1000)==1000,然后再运行第二个循环测试rand(1,1000)==rand(1,1000)。 - nobody
尽管如你所说,两者最终都得到了预期的1/1000,这减轻了担忧。 - nobody
你不应该仅仅依赖实验证据,最多只能作为一种指示。更好的方法是分析随机算法,以确定前提是否正确。 - paxdiablo
@Vinko,我并不是要贬低你的方法(+1作为道歉)。它表明了(正如你所指出的那样)PHP RNG是一个不错的选择。许多线性同余算法几乎可以保证在整个范围内不会连续两次得到相同的数字(尽管模1000可能会更频繁地发生这种情况)。我只是想说,我更喜欢有理有据的证据而不是经验主义的证据。我也同意证明它的工作量很大。由于大多数(非数学家)人并不真正关心他们的随机数有多随机,所以这并不值得。 - paxdiablo
显示剩余4条评论

8

是的,rand(1,1000) = 1000 和 rand(1,1000) = rand(1,1000) 的概率是相等的。

想象一下掷两个骰子。在你掷第一个骰子之后,第二个骰子掷出与第一个骰子相同的点数的概率是多少?是1/6。

现在,在1到6之间写下一个数字,然后掷一个骰子。这个骰子掷出与你刚才写下的数字相同的概率是1/6。


很好的解释,但我不能确定只掷一次骰子并匹配一个数字是否比掷两次(或掷两个骰子)并使它们显示相同的数字更有可能... - Ropstah
我不得不反对这个答案。虽然第一句话对于真正的随机事件是正确的,但计算机上的随机数生成器通常并不是真正的随机。事实上,如果您使用线性同余生成器,连续两个数字相同几乎是肯定的(受模数影响)。 - paxdiablo

3

如果随机数生成器是真正的随机的,那么两种方法产生的结果相同。然而,计算机随机数生成器并不完美。我怀疑这些缺陷足够重要,但想要确定的唯一方法就是尝试它——尽可能长时间地运行测试,看是否有偏差。你至少需要数百万个随机数。


+1 考虑到大多数基于计算机的“随机”数生成器的非随机性。 - paxdiablo

2
这并不是直接回答你的问题,但你可能想看一下 mt_rand()。PHP文档中指出:
许多旧版的libc随机数生成器具有可疑或未知的特性,并且速度较慢。默认情况下,PHP使用libc随机数生成器和rand()函数。mt_rand()函数是其替代品,它使用一个具有已知特性的随机数生成器,使用Mersenne Twister算法,可以比平均libc rand()提供的随机数快四倍。
来自于http://www.php.net/manual/en/function.mt-rand.php

1
大多数随机生成器的工作方式是,输出并不是真正的随机,而是基于一个算法,应该使返回的值看起来是随机和分布的。基于这一点,我认为你实际上连续两次得到相同数字的概率比在现实世界中使用两个完全无关的“随机生成器”要小。

编辑:话虽如此,我对php中默认随机生成器的工作原理没有任何内部信息。


0

选项1保证是正确的。

我不认为我在过去学习了足够的概率和统计知识,以便判断选项2是否正确。

然而,我学到了一个重要的经验教训,那就是永远不要相信别人的随机数生成器,除非你运行测试程序来了解它的真正随机性。

在您的情况下,我建议您通过两个选项运行几百万个测试用例,并查看选项2是否产生与选项1类似的统计数据。


从理论上讲,它们是相同的。 - nobody

-4

理论上,是的,这两个表达式具有完全相同的真实概率。这是假设 PHP 的随机数生成器确实是随机的 - 如果不是,一个表达式将比另一个更有可能。

最好的方法是运行一个实验(数千次迭代)并观察发生了什么。


1
这绝对不是最佳方法。即使有数百万次迭代,实验证据也只能在最好的情况下给出指示。最佳方法是确定性的,在其中你会检查算法。 - paxdiablo

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