PHP Conference Japan 2024

srand

(PHP 4, PHP 5, PHP 7, PHP 8)

srand播种随机数生成器

描述

srand(?int $seed = null, int $mode = MT_RAND_MT19937): void

使用 seed 播种随机数生成器,如果 seed0,则使用随机值。

注意: 无需使用 srand()mt_srand() 播种随机数生成器,因为这是自动完成的。

警告

因为 Mt19937(“梅森旋转法”)引擎只接受单个 32 位整数作为种子,所以可能的随机序列数量仅限于 232(即 4,294,967,296),尽管 Mt19937 的周期非常大,为 219937-1。

当依赖于隐式或显式随机播种时,重复项会更早出现。根据生日问题,在随机生成少于 80,000 个种子后,重复种子的概率为 50%。随机生成大约 30,000 个种子后,重复种子的概率为 10%。

这使得 Mt19937 不适合那些不允许出现重复序列的应用程序。如果需要可重复的播种,Random\Engine\Xoshiro256StarStarRandom\Engine\PcgOneseq128XslRr64 引擎都支持更大的种子,这些种子不太可能随机碰撞。如果不需要可重复性,Random\Engine\Secure 引擎提供密码学安全的随机性。

注意: 从 PHP 7.1.0 开始,srand() 已成为 mt_srand() 的别名。

参数

seed

使用线性同余生成器生成的数值填充状态,该生成器使用 seed(解释为无符号 32 位整数)进行播种。

如果省略 seed 或为 null,则将使用随机的无符号 32 位整数。

返回值

不返回值。

变更日志

版本 描述
8.3.0 seed 现在可以为空。
7.1.0 srand() 已成为 mt_srand() 的别名。

参见

添加注释

用户贡献的注释 13 条注释

harmen at no dot spam dot rdzl dot nl
15 年前
为了生成每天不同的随机数,我使用了 Unix 纪元后的天数作为种子

<?php
srand
(floor(time() / (60*60*24)));
echo
rand() % 100;
?>

我的提供商最近升级了 php 服务器,调用 srand(seed) 似乎不再设置种子了。要让 srand 设置种子,请将以下行添加到您的 .htaccess 文件中

php_value suhosin.srand.ignore 0

感谢 doc_z (http://www.webmasterworld.com/php/3777515.htm)

Harmen
Niels Keurentjes
13 年前
请记住,许多 PHP 安装(如 Debian 和 DirectAdmin)默认安装的 Suhosin 补丁出于加密安全原因完全禁用了 srand 和 mt_srand 函数。要在 Suhosin 加固的服务器上从固定种子生成可重复的随机数,您需要包含您自己的伪随机数生成器代码。
rjones at ditzed dot org
23 年前
使用如 [email protected] 在这些用户注释顶部提到的 srand() 种子 “(double)microtime()*1000000”。

使用任何其他种子的最显著影响是,每次调用脚本时,您的随机数往往会遵循相同或非常相似的序列。

请注意以下脚本

<?php
srand
($val);

echo
rand(0, 20) . ", ";
echo
rand(0, 20) . ", ";
echo
rand(0, 20) . ", ";
echo
rand(0, 20) . ", ";
echo
rand(0, 20);
?>

如果使用常量播种生成器,例如数字 5($val = 5),则生成的序列始终相同,在本例中为 (0, 18, 7, 15, 17)(至少对我来说是这样,不同的处理器/处理器速度/操作系统/操作系统版本/PHP 版本/Web 服务器软件可能会生成不同的序列)。

如果使用 time() 播种生成器,则序列更随机,但非常接近的调用将具有相似的输出。

如上面的 [email protected] 所建议,最好的种子是 (double) microtime() * 1000000,因为它提供了最大的伪随机性。实际上,它足够随机以满足大多数用户。
在一个测试程序中,生成了 100000 个介于 1 和 20 之间的随机数,结果相当均衡,每个数字的平均结果为 5000,误差大约为 100。每次调用的偏差各不相同。
edublancoa at gmail dot com
19年前
srand 的另一个用途是在确定的时间间隔内获得相同的 rand 值。例如:你有一个包含 100 个元素的数组,你需要每天获得一个随机项,但不能在 24 小时内更改(想象一下“今日照片”或类似的)。
<?php
$seed
= floor(time()/86400);
srand($seed);
$item = $examplearray[rand(0,99)];
?>
在 24 小时内每次加载页面时,你都会获得相同的值。
einenlum dot com邮箱联系
11个月前
请记住,现在 srand 是 mt_srand 的别名,但它们以前的行为有所不同。这意味着在使用 srand 时,你不应该遵循 srand 的文档,而应该遵循 mt_srand 的文档。

要将种子重置为随机值,`mt_srand(0)`(或 `srand(0)`)不起作用。它将种子设置为 0。要将种子重置为随机值,必须使用 `mt_srand()`(或 `srand()`)。

<?php

$arr
= [0, 1, 2, 3, 4];

srand(1); // 现在它们是别名,也可以使用 mt_srand(1)
$keys = array_rand($arr, 2); // 结果并非如预期的那样随机

srand(0); // 现在它们是别名,也可以使用 mt_srand(0)
$keys = array_rand($arr, 2); // 结果仍然不随机!

srand(); // 现在它们是别名,也可以使用 mt_srand()
$keys = array_rand($arr, 2); // 再次随机

?>
Glauco Lins
9年前
srand 和 mt_srand 每个进程 ID 只初始化一次。

在第一次调用 "srand"、"mt_srand"、"rand"、"mt_rand"、"shuffle" 或任何其他类似 rand 的函数之后,你无法重新设定你的 rand 算法的种子。

我遇到一个问题,在 fork 我的进程后,所有子进程都生成完全相同的 rand 值。
这是由于父进程中第一次调用了 "shuffle",所以我无法重新设定子进程的种子。

为了解决我的问题,我简单地调用了 N 次 "rand" 来偏移子 rand 生成器。

# 通过其 PID 偏移子 rand 生成器
$n = (getmypid() % 100) * (10 * abs(microtime(true) - time()));
for ($n; $n > 0; $n--) {
rand(0, $n);
}

由于每个 pcntl_fork 需要一段时间才能完成,因此 microtime 提供了除 PID 增量之外的额外偏移量。

这段小代码在最坏的情况下也会进行 1000 次迭代。
mlwmohawk at mohawksoft dot com
23 年前
srand() 很难正确使用。如果可以避免,你永远不应该在一个 php 进程中多次播种随机数生成器,否则你的随机性将限制在你的种子的来源。

microtime 函数的微秒部分的分辨率非常有限,这就是为什么 make_seed 函数被添加到文档中的原因。你永远不应该两次获得相同的种子。

在较后的 CVS 版本中,如果之前没有调用 srand(),PHP 将在执行 rand() 之前播种随机生成器。
匿名用户
23 年前
我有一个每天更改一段文本的随机循环器,我使用以下代码来确保种子足够唯一。

$tm = time();
$today = mktime(0, 0, 0, (int)date("n", $tm), (int)date("j", $tm), (int)date("Y", $tm));
srand($today / pi());

π 在整个过程中效果很好,而且运行起来很顺利。任何其他大的十进制数也可以,但 π 是最常见的“大”数。
rjones at ditzed dot org
23 年前
关于 srand() 用法的一些补充说明

如果你正在使用模块化编程,最好尝试从父脚本而不是从你可能正在使用的任何模块(使用 REQUIRE 或 INCLUDE)调用 srand 例程。
这样可以避免从不同的模块多次调用 srand() 的可能性。

当然,此解决方案的缺陷在于使用其他程序员编写的模块时,或为其他程序员编写模块时。
你不能依赖其他程序员在调用模块化函数之前调用 srand 函数,因此在这种情况下,你必须在模块中包含 srand 函数。

如果你为其他程序员制作模块,那么最好记录你已经调用了 srand 函数这一事实。
或者,如果你使用其他程序员编写的模块化函数,请检查他们的文档或源代码。
MakeMoolah at themail dot com
23 年前
对不起……好吧,忘记我上面说的^一半吧。

可以证明我的例子的代码如下

<?php
srand
(5);
echo(
rand(1, 10));
srand(5);
echo(
rand(1, 10));
srand(5);
echo(
rand(1, 10));
?>

每次你都应该得到相同的答案,但如果你这样做

<?php
srand
(5);
echo(
rand(1, 10));
echo(
rand(1, 10));
echo(
rand(1, 10));
?>

那么答案就会不同,你就会让随机数公式发挥作用。
hagen at von-eitzen dot de
24年前
确保 srand 只调用一次至关重要。
如果调用隐藏在你包含的第三方代码中的某个地方,这有点困难。例如,我使用了一个标准的横幅脚本,该脚本似乎工作得很好,它将
三个随机横幅放在一个框架中。但从长远来看,选择似乎
有些偏差——可能是因为 srand 每次横幅调用一次,而不是
每次运行调用一次。
如果随机数生成器像 PERL 中那样工作就好了:如果你在脚本中从未调用过 srand 之前就使用随机函数,
则在之前(并自动使用一个好的种子,希望如此)调用 srand。
我建议应该这样做

<?php
if (!$GLOBALS["IHaveCalledSrandBefore"]++) {
srand((double) microtime() * 1000000);
}
?>

(根据具体情况,也可以使用静态变量)
bootc at bootc dot net
19年前
好的,总结一下大家到目前为止所说的内容

1. 如果你可以避免,请不要多次播种 RNG!
2. 如果你使用的是 PHP < 4.2.0,你必须自己播种 RNG。
3. 使用素数乘数到 microtime() 几乎没有作用。请改用 Mersenne Twister。
4. 你可以使用 Mersenne Twister PRNG 和 mt_rand 和 mt_srand 函数。这更快,也更随机。
akukula at min dot pl
23 年前
调用 srand((double)microtime()*1000000),
然后 $a=rand(1000000,9999999), 然后 srand((double)microtime()*$a)
不会增加任何熵:rand 和 srand 的执行时间是
常数,因此第二个 microtime() 不会产生任何真正令人兴奋的结果。你可以安全地只使用第一个 srand()。
To Top