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 現在可以為 null。
7.1.0 srand() 已成為 mt_srand() 的別名。

參見

  • rand() - 產生一個隨機整數
  • getrandmax() - 顯示最大的可能隨機值
  • mt_srand() - 設定梅森旋轉演算法亂數產生器的種子

新增註解

使用者貢獻的註解 13 則註解

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
14
Niels Keurentjes
13 年前
請記住,Suhosin 修補程式預設安裝在許多 PHP 安裝中,例如 Debian 和 DirectAdmin,為了加密安全性原因,完全停用了 srand 和 mt_srand 函式。若要在 Suhosin 強化的伺服器上從固定種子產生可重現的亂數,您將需要包含您自己的虛擬隨機產生器程式碼。
1
rjones at ditzed dot org
23 年前
使用 richard@zend.com 在這些使用者註解頂部提到的 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 版本/網路伺服器軟體可能會產生不同的序列)。

如果您使用 time() 設定產生器的種子,則序列會更加隨機,但非常接近的調用會有相似的輸出。

如 richard@zend.com 上述建議,最佳的種子是 (double) microtime() * 1000000,因為這提供了最大的虛擬隨機性。事實上,它足夠隨機,適合大多數使用者。
在 1 到 20 之間的 100000 個隨機數的測試程式中,結果相當平衡,每個數字的平均結果為 5000 個,誤差約為 100 個。每種情況下的偏差都隨著每次調用而變化。
1
edublancoa at gmail dot com
19 年前
srand 的另一個用途是在確定的時間間隔內取得相同的 rand 值。範例:您有一個包含 100 個元素的陣列,而且您需要每天取得一個隨機項目,但不要在 24 小時內變更(只要想像「今日照片」或類似的內容)。
<?php
$seed
= floor(time()/86400);
srand($seed);
$item = $examplearray[rand(0,99)];
?>
您在整個 24 小時內每次載入頁面都會取得相同的值。
0
contact at 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); // 又變回隨機了

?>
0
Glauco Lins
9 年前
srand 和 mt_srand 在每個進程 ID 中只初始化一次。

在第一次使用 "srand"、"mt_srand"、"rand"、"mt_rand"、"shuffle" 或任何其他類似 rand 的函數後,您就無法重新設定 rand 演算法的種子。

我遇到一個問題,在 fork 我的進程後,所有子進程都產生完全相同的 rand 值。
這是因為父進程第一次呼叫 "shuffle",所以我無法重新設定子進程的種子。

為了解決我的問題,我簡單地呼叫 "rand" N 次,來偏移子進程的 rand 產生器。

# 根據子進程的 PID 偏移其 rand 產生器
$n = (getmypid() % 100) * (10 * abs(microtime(true) - time()));
for ($n; $n > 0; $n--) {
rand(0, $n);
}

由於每個 pcntl_fork 都需要一段時間才能完成,microtime 提供了額外的偏移量,而不僅僅是 PID 遞增。

這段小程式在最壞的情況下也會執行 1000 次迭代。
0
mlwmohawk at mohawksoft dot com
23 年前
srand() 非常難以正確使用。您不應該在每個 php 進程中設定隨機數產生器的種子超過一次,如果您這樣做,您的隨機性將僅限於您的種子來源。

microtime 函數的微秒部分具有非常有限的解析度,這就是為什麼在文件中加入 make_seed 函數的原因。您永遠不應該獲得相同的種子兩次。

在後來的 CVS 版本中,如果先前沒有呼叫 srand(),PHP 將在執行 rand() 之前設定隨機產生器的種子。
0
Anonymous
23 年前
我有一個每天會更改一段文字的隨機輪轉器,我使用以下程式碼來確保種子夠獨特。

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

pi 對整個過程都非常有效,而且效果很好。任何其他大的十進制數也都可以,但 pi 是最常見的「大」數。
0
rjones at ditzed dot org
23 年前
關於 srand() 使用的題外話

如果您正在使用模組化程式設計,最好嘗試從父腳本而不是您可能正在使用的任何模組 (使用 REQUIRE 或 INCLUDE) 呼叫 srand 例程。
這樣您就可以避免從不同的模組多次呼叫 srand() 的可能性。

當然,這個解決方案的缺陷在於使用其他程式設計師產生的模組,或者為其他程式設計師產生模組時。
您不能依賴其他程式設計師在呼叫模組化函數之前呼叫 srand 函數,因此在這種情況下您必須將 srand 函數包含在模組中。

如果您產生供其他程式設計師使用的模組,那麼最好記錄您已經呼叫過 srand 函數的事實。
或者如果您使用其他人產生的模組化函數,請檢查他們的說明文件或他們的原始程式碼。
0
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));
?>

那麼答案將會不同,而您將讓隨機數公式執行其任務。
-1
hagen at von-eitzen dot de
24 年前
確保 srand 只被呼叫一次非常重要。
如果呼叫隱藏在您包含的第三方程式碼中的某個位置,這會有點困難。例如,我使用了一個標準的橫幅腳本,它*似乎*運作良好,將
三個隨機橫幅放在一個框架中。但從長遠來看,選擇似乎
有點偏差 - 可能是因為每個橫幅呼叫一次 srand,而不是
每次執行一次。
如果隨機數產生器像 PERL 中那樣工作會更好:如果您在腳本中從未呼叫過 srand 就使用隨機函數,
srand 會在之前被調用 (並自動使用一個好的種子,希望如此)。
我建議應該做類似這樣的事情

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

(根據情況,也可以使用靜態變數代替)
-1
bootc at bootc dot net
19 年前
好的,總結一下目前為止大家所說的

1. 如果可以的話,請不要設定 RNG 的種子超過一次!
2. 如果您使用的是 PHP < 4.2.0,您必須自己設定 RNG 的種子。
3. 使用質數乘數來乘以 microtime() 可能作用不大。請改用 Mersenne Twister。
4. 您可以使用 mt_rand 和 mt_srand 函數搭配 Mersenne Twister PRNG。這更快,而且更隨機。
-1
akukula at min dot pl
23 年前
呼叫 srand((double)microtime()*1000000),
然後 $a=rand(1000000,9999999),然後 srand((double)microtime()*$a)
不會增加熵值:rand 和 srand 的執行時間是
恆定的,因此第二個 microtime() 不會產生任何真正令人著迷的東西。您可以安全地只使用第一個 srand()。
To Top