檢視原始碼 rand (stdlib v6.2)
偽隨機數產生
此模組提供偽隨機數產生,並實作多種基礎產生器演算法。大多數是透過外掛框架提供,該框架會為基礎產生器新增功能。
在此模組文件的結尾,有一些利基演算法,它們不使用此模組的標準外掛框架。它們可能適用於特殊目的,例如當品質不重要時的短產生時間、用於播種其他產生器等。
外掛框架
- 在程序字典中操作產生器狀態。
- 自動播種。
- 手動播種支援,以避免常見的陷阱。
- 產生任何範圍內的整數,具有均勻分佈,且無明顯偏差。
- 產生任何範圍內的整數,範圍大於基礎產生器,具有均勻分佈。
- 產生具有均勻分佈的浮點數。
- 產生具有常態分佈的浮點數。
- 產生任意數量的位元組。
基礎產生器演算法實作了 Sebastiano Vigna 的 Xoroshiro 和 Xorshift 演算法。在迭代過程中,它們會產生一個大的整數(至少 58 位元),並對幾個大整數的狀態進行操作。
為了產生具有常態分佈的數字,將 Marsaglia 和 Tsang 的 Ziggurat 方法用於基礎產生器的輸出。
對於大多數演算法,都提供了跳躍函數來產生不重疊的序列。跳躍函數執行的計算相當於大量重複的狀態迭代,但執行時間大約相當於每個產生器位元的一次常規迭代。
exsss
,預設演算法 (自 OTP 22.0 起)
Xorshift116**,58 位元精確度,週期為 2^116-1跳躍函數:相當於 2^64 次呼叫
這是 Xorshift116 產生器與 David Blackman 和 Sebastiano Vigna 在 2018 年論文中提出的 StarStar 加密器結合:擾亂線性偽隨機數產生器
產生器不使用 58 位元旋轉,因此它比 Xoroshiro116 產生器更快,並且與 StarStar 加密器結合使用時,它不像
exrop
(Xoroshiro116+) 那樣有任何弱低位。唉,這種組合比
exrop
慢約 10%,但儘管如此,由於其統計特性,它是預設演算法。exro928ss
(自 OTP 22.0 起)
Xoroshiro928**,58 位元精確度,週期為 2^928-1跳躍函數:相當於 2^512 次呼叫
這是 David Blackman 和 Sebastiano Vigna 在 2018 年論文中提出的 58 位元版本的 Xoroshiro1024**:擾亂線性偽隨機數產生器,在 64 位元 Erlang 系統上執行速度僅比預設
exsss
演算法慢約 40%,但週期更長且統計特性更好,但另一方面,狀態較大。非常感謝 Sebastiano Vigna 在 58 位元改編方面的幫助。
exrop
(自 OTP 20.0 起)
Xoroshiro116+,58 位元精確度,週期為 2^116-1跳躍函數:相當於 2^64 次呼叫
exs1024s
(自 OTP 20.0 起)
Xorshift1024*,64 位元精確度,週期為 2^1024-1跳躍函數:相當於 2^512 次呼叫
exsp
(自 OTP 20.0 起)
Xorshift116+,58 位元精確度,週期為 2^116-1跳躍函數:相當於 2^64 次呼叫
這是先前預設演算法(
exsplus
,已棄用)的更正版本,該版本已被 Xoroshiro116+ (exrop
) 取代。由於此演算法不使用旋轉,因此它的執行速度比exrop
快一點(例如 < 15%)(必須執行 58 位元旋轉,而沒有原生指令)。請參閱演算法的首頁。
預設演算法
目前的預設演算法是exsss
(Xorshift116**)。如果需要特定演算法,請務必始終使用seed/1
來初始化狀態。
預設的演算法在 Erlang/OTP 版本之間可能會變更,並且選擇的演算法具有高速、小狀態和「夠好」的統計特性。
舊演算法
未記錄(舊)演算法已棄用,但仍實作,因此依賴它們的舊程式碼將產生與以前相同的偽隨機序列。
注意
現在未記錄的演算法的實作存在許多問題,這就是它們被棄用的原因。新演算法速度稍慢,但沒有這些問題
均勻整數範圍在機率分佈中存在偏差,對於小範圍來說不顯著,但對於小於產生器精度的較大範圍,產生較小數字的機率可能是產生較大數字的機率的兩倍。
大於或等於產生器精度的均勻整數範圍使用浮點回退,該回退僅計算 52 位元,這小於請求的範圍,因此請求範圍內的所有數字甚至不可能產生。
均勻浮點數具有不均勻密度,因此小值(例如小於 0.5)的間隔較小,隨著產生值接近 0.0 而減少,儘管對於足夠大的子範圍仍均勻分佈。新演算法產生形式為
N * 2.0^(-53)
的均勻分佈浮點數,因此它們等間隔。
產生器狀態
每次產生隨機數時,都會使用狀態來計算它,從而產生新狀態。狀態可以是隱含的,也可以是明確的參數和回傳值。
具有隱含狀態的函數在程序字典中,在鍵rand_seed
下儲存的狀態上運作。如果呼叫函數時該鍵不存在,則會使用預設演算法自動呼叫seed/1
,並建立一個相當不可預測的種子。
具有明確狀態的函數不使用程序字典。
範例
簡單用法;如果尚未完成,則使用非固定種子建立並播種預設演算法,並產生兩個均勻分佈的浮點數。
R0 = rand:uniform(),
R1 = rand:uniform(),
使用指定的演算法
_ = rand:seed(exro928ss),
R2 = rand:uniform(),
使用具有固定種子的指定演算法
_ = rand:seed(exro928ss, {123, 123534, 345345}),
R3 = rand:uniform(),
使用具有非固定種子的函數式 API
S0 = rand:seed_s(exsss),
{R4, S1} = rand:uniform_s(S0),
產生教科書基本形式 Box-Muller 標準常態分佈數字
R5 = rand:uniform_real(),
R6 = rand:uniform(),
SND0 = math:sqrt(-2 * math:log(R5)) * math:cos(math:pi() * R6)
產生標準常態分佈數字
{SND1, S2} = rand:normal_s(S1),
產生平均值為 -3 且變異數為 0.5 的常態分佈數字
{ND0, S3} = rand:normal_s(-3, 0.5, S2),
產生數字的品質
注意
內建的隨機數產生器演算法並非加密強大的。如果需要加密強大的隨機數產生器,請使用類似
crypto:rand_seed/0
的內容。
對於除了 exro928ss
和 exsss
之外的所有這些產生器,最低位元的隨機行為略遜於所有其他位元。exrop
(和 exsp
)的 1 位元,以及 exs1024s
的 3 位元。例如,請參閱Xoroshiro128+產生器原始碼中的此說明
除了通過 BigCrush 之外,此產生器還通過了 PractRand 測試套件,最高可達(並包含)16TB,但二進位階級測試除外,由於最低位元是 LFSR,因此該測試會失敗;所有其他位元都通過了所有測試。我們建議使用符號測試來提取隨機布林值。
如果這是一個問題;若要使用這些演算法產生布林值,請使用如下內容
(rand:uniform(256) > 128) % -> boolean()
((rand:uniform(256) - 1) bsr 7) % -> 0 | 1
對於一般範圍,exrop
的 N = 1
,以及 exs1024s
的 N = 3
(((rand:uniform(Range bsl N) - 1) bsr N) + 1)
此模組中的浮點產生函數在從整數轉換時會浪費最低位元,因此它們可以避免此問題。
利基演算法
利基演算法 API 包含不使用外掛框架的特殊用途演算法,主要是為了效能考量。
由於這些演算法缺乏外掛框架支援,因此在範圍內產生數字(而不是基礎產生器的範圍)可能會成為問題。
至少有四種方法可以做到這一點,假設Range
小於產生器的範圍
模數
若要產生範圍在0..Range-1
中的數字V
產生一個數字
X
。
使用V = X rem Range
作為您的值。此方法使用
rem
,即整數除法的餘數,這是一個緩慢的操作。產生器的低位元會直接傳播到產生值,因此如果產生器的低位元存在弱點,此方法也會傳播它們。
如果
Range
不是產生器範圍的除數,則產生的數字會產生偏差。範例假設產生器產生一個位元組,也就是說,產生器範圍是
0..255
,而所需的範圍是0..99
(Range = 100
)。那麼有 3 個產生器輸出會產生值0
,它們是;0
、100
和200
。但是只有 2 個產生器輸出會產生值99
,它們是;99
和199
。因此,0..55
中值V
的機率是其他值56..99
的機率的 3/2 倍。如果
Range
比產生器範圍小得多,則此偏差會變得難以偵測。經驗法則是,如果Range
小於產生器範圍的平方根,則偏差就夠小。範例當
Range = 20
時的位元組產生器。有 12 個 (256 div 20
) 產生最高數字的可能性,以及一個額外產生數字V < 16
(256 rem 20
) 的可能性。因此,產生低數字的機率相對於高數字是 13/12。若要以一定的信心偵測出差異,您需要產生比產生器範圍多得多的數字,在這個小例子中是256
。
截斷乘法
當您有一個範圍為 2 的冪的產生器 (0..2^Bits-1
) 時,若要產生範圍在0..Range-1
之間的數字V
,產生一個數字
X
。
請使用V = X * Range bsr Bits
作為您的值。如果乘法
X * Range
產生大數,此方法會變得非常緩慢。產生器的高位元會傳播到產生的值,因此如果產生器的高位元有缺陷,此方法也會傳播這些缺陷。
如果
Range
不是產生器範圍的除數,則產生的數字會有偏差,幾乎與上面的模數方法相同。
位移或遮罩
當您有一個範圍為 2 的冪的產生器 (0..2^Bits
) 時,若要產生範圍為 2 的冪的數字 (0..2^RBits-1
),產生一個數字
X
。
請使用V = X band ((1 bsl RBits)-1)
或V = X bsr (Bits-RBits)
作為您的值。使用
band
進行遮罩會保留低位元,而使用bsr
進行右移會保留高位元,因此如果產生器在高位元或低位元有缺陷,請選擇正確的運算子。如果產生器的範圍不是 2 的冪,但仍然使用此方法,則會引入與上面的模數方法相同方式的偏差。
拒絕
產生一個數字
X
。
如果X
在範圍內,則將其用作您的值,否則拒絕它並重複。理論上,此方法不一定會完成,但實際上您要確保拒絕的機率很低。然後,另一次迭代的機率會呈指數級下降,因此預期的平均迭代次數通常在 1 到 2 之間。此外,由於基礎產生器是全長的產生器,因此最終必須產生會中斷迴圈的值。
這些方法可以組合使用,例如使用模數方法,並且僅當產生器值會產生偏差時才使用拒絕。或者使用位移或遮罩來縮減產生器值的大小,以便截斷乘法不會產生大數。
在範圍
0..1
中產生浮點數(IEEE 745 雙精度,具有 53 位尾數)的建議方法(即0.0 =< V < 1.0
)是產生一個 53 位數字X
,然後使用V = X * (1.0/((1 bsl 53)))
作為您的值。這將會產生形式為 N*2^-53 的值,且範圍內每個可能的 N 的機率都相等。
摘要
類型
演算法特定的內部狀態
可以列印或儲存到檔案的演算法相依狀態。
演算法特定的內部狀態
演算法特定的內部狀態
演算法特定的內部狀態
演算法特定的內部狀態
演算法特定的內部狀態
1 .. (16#1ffb072 bsl 29) - 2
產生器種子值。
演算法特定狀態
演算法相依狀態。
0 .. (2^58 - 1)
0 .. (2^64 - 1)
外掛程式架構 API
使用程序字典中的狀態,產生隨機位元組作為 t:binary()
。
產生隨機位元組作為 t:binary()
。
匯出種子值。
匯出種子值。
向前跳躍產生器狀態。
向前跳躍產生器狀態。
產生具有標準常態分配的隨機數。
產生具有指定常態分配 𝒩 (μ, σ²) 的隨機數。
產生具有標準常態分配的隨機數。
產生具有指定常態分配 𝒩 (μ, σ²) 的隨機數。
設定隨機數產生器的種子並選擇演算法。
設定隨機數產生器的種子並選擇演算法。
設定隨機數產生器的種子並選擇演算法。
設定隨機數產生器的種子並選擇演算法。
使用程序字典中的狀態,產生均勻分配的隨機數 0.0 =< X < 1.0
。
使用程序字典中的狀態,產生均勻分配的隨機整數 1 =< X =< N
。
使用程序字典中的狀態,產生均勻分配的隨機數 0.0 < X < 1.0
。
產生均勻分配的隨機數 0.0 < X < 1.0
。
產生均勻分配的隨機數 0.0 =< X < 1.0
。
產生均勻分配的隨機整數 1 =< X =< N
。
類型
-type alg() :: builtin_alg() | atom().
-type alg_handler() :: #{type := alg(), bits => non_neg_integer(), weak_low_bits => non_neg_integer(), max => non_neg_integer(), next := fun((alg_state()) -> {non_neg_integer(), alg_state()}), uniform => fun((state()) -> {float(), state()}), uniform_n => fun((pos_integer(), state()) -> {pos_integer(), state()}), jump => fun((state()) -> state())}.
-type alg_state() :: exsplus_state() | exro928_state() | exrop_state() | exs1024_state() | exs64_state() | dummy_state() | term().
-type builtin_alg() :: exsss | exro928ss | exrop | exs1024s | exsp | exs64 | exsplus | exs1024 | dummy.
-type dummy_state() :: uint58().
演算法特定的內部狀態
可以列印或儲存到檔案的演算法相依狀態。
-opaque exro928_state()
演算法特定的內部狀態
-opaque exrop_state()
演算法特定的內部狀態
-opaque exs64_state()
演算法特定的內部狀態
-opaque exs1024_state()
演算法特定的內部狀態
-opaque exsplus_state()
演算法特定的內部狀態
-type mwc59_state() :: 1..133850370 bsl 32 - 1 - 1.
1 .. (16#1ffb072 bsl 29) - 2
產生器種子值。
整數列表會直接設定產生器的內部狀態,在演算法相依的值檢查和遮罩為正確的字組大小之後。整數的數量必須等於產生器中狀態字組的數量。
單一整數會用作 SplitMix64 產生器的初始狀態。然後,該整數的循序輸出值會用於設定產生器的內部狀態,在遮罩為正確的字組大小之後,並且如果需要則避免零值。
傳統的三整數組成的種子會透過演算法相依的雜湊函數傳遞,以建立產生器的初始狀態。
-type splitmix64_state() :: uint64().
演算法特定狀態
-type state() :: {alg_handler(), alg_state()}.
演算法相依狀態。
-type uint58() :: 0..1 bsl 58 - 1.
0 .. (2^58 - 1)
-type uint64() :: 0..1 bsl 64 - 1.
0 .. (2^64 - 1)
外掛程式架構 API
-spec bytes(N :: non_neg_integer()) -> Bytes :: binary().
使用程序字典中的狀態,產生隨機位元組作為 t:binary()
。
-spec bytes_s(N :: non_neg_integer(), State :: state()) -> {Bytes :: binary(), NewState :: state()}.
產生隨機位元組作為 t:binary()
。
對於指定的整數 N >= 0
,產生一個具有該數量隨機位元組的 binary/0
。
-spec export_seed() -> undefined | export_state().
匯出種子值。
傳回外部格式的隨機數狀態。與 seed/1
一起使用。
-spec export_seed_s(State :: state()) -> export_state().
匯出種子值。
以外部格式傳回亂數產生器狀態。與 seed/1
搭配使用。
-spec jump() -> NewState :: state().
向前跳躍產生器狀態。
向前跳躍產生器狀態。
執行一個演算法特定的 State
跳躍計算,其效果等同於大量狀態迭代。請參閱此模組的演算法列表。
傳回 NewState
。
此功能可用於從一個起始狀態建立許多不重疊的亂數序列。
如果沒有為 State
的演算法實作跳躍函數,此函數會引發 not_implemented
錯誤例外。
-spec normal() -> X :: float().
產生具有標準常態分配的隨機數。
與 normal_s/1
類似,但操作的是儲存在程序字典中的狀態。傳回產生的數字 X
。
產生具有指定常態分配 𝒩 (μ, σ²) 的隨機數。
與 normal_s/3
類似,但操作的是儲存在程序字典中的狀態。傳回產生的數字 X
。
產生具有標準常態分配的隨機數。
從指定的 State
,產生一個具有標準常態分佈的亂數 X ::
float/0
,也就是平均值為 0.0
,變異數為 1.0
。
-spec normal_s(Mean, Variance, State) -> {X :: float(), NewState :: state()} when Mean :: number(), Variance :: number(), State :: state().
產生具有指定常態分配 𝒩 (μ, σ²) 的隨機數。
從指定的 State
,產生一個具有常態分佈 𝒩 (μ, σ²) 的亂數 X ::
float/0
,也就是 𝒩 (平均值,變異數),其中 變異數 >= 0.0
。
設定隨機數產生器的種子並選擇演算法。
與 seed_s(Alg_or_State)
相同,但也會將產生的狀態儲存在程序字典中。
參數 default
是已實作的預設演算法的別名(自 OTP 24.0 起)。
設定隨機數產生器的種子並選擇演算法。
與 seed_s(Alg, Seed)
相同,但也會將產生的狀態儲存在程序字典中。
Alg = default
是已實作的預設演算法的別名(自 OTP 24.0 起)。
-spec seed_s(Alg | State) -> state() when Alg :: builtin_alg() | default, State :: state() | export_state().
設定隨機數產生器的種子並選擇演算法。
使用參數 Alg
,選擇該演算法,並使用合理且不可預測的時間相依資料來設定亂數產生器的種子。
Alg = default
是預設演算法的別名(自 OTP 24.0 起)。
使用參數 State
,重新建立狀態並傳回。另請參閱 export_seed/0
。
-spec seed_s(Alg, Seed) -> state() when Alg :: builtin_alg() | default, Seed :: seed().
設定隨機數產生器的種子並選擇演算法。
從指定的 seed/0
整數,為指定的演算法建立並傳回一個產生器狀態。
Alg = default
是已實作的預設演算法的別名(自 OTP 24.0 起)。
-spec uniform() -> X :: float().
使用程序字典中的狀態,產生均勻分配的隨機數 0.0 =< X < 1.0
。
與 uniform_s/1
類似,但操作的是儲存在程序字典中的狀態。傳回產生的數字 X
。
-spec uniform(N :: pos_integer()) -> X :: pos_integer().
使用程序字典中的狀態,產生均勻分配的隨機整數 1 =< X =< N
。
與 uniform_s/2
類似,但操作的是儲存在程序字典中的狀態。傳回產生的數字 X
。
-spec uniform_real() -> X :: float().
使用程序字典中的狀態,產生均勻分配的隨機數 0.0 < X < 1.0
。
與 uniform_real_s/1
類似,但操作的是儲存在程序字典中的狀態。傳回產生的數字 X
。
請參閱 uniform_real_s/1
。
產生均勻分配的隨機數 0.0 < X < 1.0
。
從指定的狀態,產生一個在值範圍 DBL_MIN =< X < 1.0
內均勻分佈的隨機浮點數。
概念上,從區間 0.0 =< R < 1.0
產生一個隨機實數 R
,然後傳回 IEEE 754 雙精度格式中最接近且向下捨入的非零正規化數字。
注意
此函數產生的數字在小數字方面比常規的
uniform_s/1
具有更好的粒度,因為尾數中的所有位元都是隨機的。這個特性,加上永遠不會傳回零的事實,對於執行例如1.0 / X
或math:log(X)
的演算法很有用。
這個概念暗示了獲得精確零的機率極低;如此之低以至於這個函數實際上永遠不會傳回 0.0
。它可能傳回的最小數字是 DBL_MIN
,也就是 2.0^(-1022)
。
此函數描述頂部所述的值範圍在技術上是正確的,但 0.0 =< X < 1.0
更好地描述了產生數字的統計分佈,並且這個函數永遠不會傳回精確的 0.0
是不可能觀察到的。
對於所有子範圍 N*2.0^(-53) =< X < (N+1)*2.0^(-53)
,其中 0 =< integer(N) < 2.0^53
,產生該範圍內數字的機率是相同的。與 uniform_s/1
產生的數字比較。
為偶然的小數字產生額外的隨機位元會消耗一些效能。此函數比常規的 uniform_s/1
慢約 20%。
產生均勻分配的隨機數 0.0 =< X < 1.0
。
從指定的 State
,產生一個在值範圍 0.0 =< X < 1.0
內均勻分佈的亂數 X ::
float/0
。傳回數字 X
和更新後的 NewState
。
產生的數字形式為 N * 2.0^(-53)
,也就是說,在區間內等距分佈。
警告
此函數可能會傳回精確的
0.0
,這對於某些應用程式可能是致命的。如果不需要這樣,您可以使用(1.0 - rand:uniform())
來取得區間0.0 < X =< 1.0
,或者改用uniform_real/0
。如果不需要任何端點,您可以使用像這樣的方式透過測試和重試來達到範圍
0.0 < X < 1.0
my_uniform() -> case rand:uniform() of X when 0.0 < X -> X; _ -> my_uniform() end.
-spec uniform_s(N :: pos_integer(), State :: state()) -> {X :: pos_integer(), NewState :: state()}.
產生均勻分配的隨機整數 1 =< X =< N
。
從指定的 State
,產生一個在指定範圍 1 =< X =< N
內均勻分佈的亂數 X ::
integer/0
。傳回數字 X
和更新後的 NewState
。
利基演算法 API
-spec exsp_jump(AlgState :: exsplus_state()) -> NewAlgState :: exsplus_state().
向前跳躍產生器狀態。
執行一個 State
跳躍計算,其效果等同於 2^64 次狀態迭代。
傳回 NewState
。
此功能可用於從一個起始狀態建立許多不重疊的亂數序列。
請參閱此模組描述頂部的跳躍函數說明。
請參閱關於為何公開此內部實作函數的 exsp_next/1
。
-spec exsp_next(AlgState :: exsplus_state()) -> {X :: uint58(), NewAlgState :: exsplus_state()}.
產生 Xorshift116+ 隨機整數和新的演算法狀態。
根據指定的 AlgState
,依照 Xorshift116+ 演算法產生一個 58 位元的隨機整數 X
和一個新的演算法狀態 NewAlgState
。
這是一個 API 函數,公開了 exsp
演算法的內部實作,使其無需外掛框架的開銷即可使用,這對於時間要求嚴苛的應用程式可能很有用。在典型的 64 位元 Erlang VM 上,這種方法的執行時間僅為透過此模組的正常外掛框架使用預設演算法的 30% (1/3) 多一點。
要設定此產生器的種子,請使用 {_, AlgState} = rand:seed_s(exsp)
或 {_, AlgState} = rand:seed_s(exsp, Seed)
,並指定一個 Seed
。
注意
此函數不提供在選定範圍內產生數字或產生浮點數的協助。在進行上述任何操作時,很容易意外地搞砸此產生器的統計特性,或失去效能優勢。請參閱此利基演算法 API 描述開頭的食譜。
另請注意此產生器存在弱低位元的注意事項。
此產生器主要以這種形式匯出,是為了效能考量。
-spec mwc59(CX0 :: mwc59_state()) -> CX1 :: mwc59_state().
產生新的 MWC59 狀態。
根據指定的產生器狀態 CX0
,依照 Multiply With Carry 產生器產生一個新的狀態 CX1
。Multiply With Carry 產生器是具有 2 的冪次方乘數和質數模數的乘法同餘產生器的有效實作。
此產生器使用乘數 2^32
和模數 16#7fa6502 * 2^32 - 1
,它們是在與 Sebastiano Vigna 合作下選擇的,以避免大數運算並仍然獲得良好的統計品質。它被命名為「MWC59」,可以寫成
C = CX0 bsr 32
X = CX0 band ((1 bsl 32)-1))
CX1 = 16#7fa6502 * X + C
由於產生器使用 2 的冪次方作為乘數,因此在 2 維和 3 維的碰撞測試和生日間隔測試中會出現統計缺陷,即使只查看產生器狀態的 MWC「數字」(即低 32 位元(乘數))也是如此。狀態的較高位元更差。
通過使用擾亂器而不是僅取出低位元,可以大大提高輸出值的品質。函數 mwc59_value32
是一個快速擾亂器,會返回一個體面的 32 位元數字。稍微慢一點的 mwc59_value
擾亂器會返回 59 位元、品質非常好的數字,而 mwc59_float
會返回品質非常好的 float/0
。
基本產生器的低位元出奇地好,因此最低 16 位元實際上通過了相當嚴格的 PRNG 測試,儘管產生器的弱點在 32 位元 MWC「數字」的高位元中。建議對產生器狀態使用 rem
,或使用位元遮罩提取最低位元,以產生範圍在 16 位元或更小的數字。請參閱此利基演算法 API 描述開頭的食譜。
在典型的 64 位元 Erlang VM 上,此產生器的執行時間不到此模組的外掛框架 API 中預設演算法的 8% (1/13)。使用 mwc59_value32
擾亂器時,總時間會變成 16% (1/6),而使用 mwc59_value
時,會變成預設演算法時間的 20% (1/5)。使用 mwc59_float
時,產生 float/0
的總時間是預設演算法時間的 60%。
注意
此產生器是針對高速應用程式的利基產生器。它的週期比預設產生器短得多,這本身就是一個品質問題,儘管在使用值擾亂器時,它通過了嚴格的 PRNG 測試。此產生器比
exsp_next/1
快得多,但品質稍低,週期短得多。
-spec mwc59_float(CX :: mwc59_state()) -> V :: float().
從產生器狀態 CX
返回一個值 V ::
float/0
,範圍為 0.0 =< V < 1.0
,例如 uniform_s/1
。
產生器狀態在轉換為 float/0
之前,會像 mwc59_value/1
一樣進行擾亂。
-spec mwc59_seed() -> CX :: mwc59_state().
建立 MWC59 產生器狀態。
類似於 mwc59_seed/1
,但它會雜湊 seed_s(atom())
的預設種子值。
-spec mwc59_seed(S :: 0..1 bsl 58 - 1) -> CX :: mwc59_state().
建立 MWC59 產生器狀態。
返回一個產生器狀態 CX
。 58 位元種子值 S
會被雜湊以建立產生器狀態,以避免相似的種子建立相似的序列。
-spec mwc59_value32(CX :: mwc59_state()) -> V :: 0..1 bsl 32 - 1.
從MWC59 狀態計算 32 位擾亂值。
從產生器狀態 CX
返回一個 32 位元值 V
。產生器狀態使用 8 位元的 xorshift 進行擾亂,這足以掩蓋基本產生器 mwc59
的統計缺陷,以產生品質尚可的數字。不過,2 維和 3 維的生日間隔和碰撞測試仍會顯示出一些問題。
在使用此擾亂器時,通常最好使用數值的高位元,而不是低位元。最低的 8 位元品質良好,並且直接從基本產生器傳遞。它們與 xorshift 中的下 8 個位元組合,使低 16 位元具有良好的品質,但在 16..31 位元的範圍內,存在較弱的位元,不應成為產生值的高位元。
因此,通常較安全的做法是移出低位元。請參閱此利基演算法 API 描述開頭的食譜。
對於小於約 16 位元的非 2 的冪次範圍(以避免過多偏差並避免大數),可以使用截斷乘法,即:(Range*V) bsr 32
,這比使用 rem
快得多。
-spec mwc59_value(CX :: mwc59_state()) -> V :: 0..1 bsl 59 - 1.
從MWC59 狀態計算 59 位擾亂值。
從產生器狀態 CX
返回一個 59 位元值 V
。產生器狀態使用 4 位元接著 27 位元的 xorshift 進行擾亂,這足以掩蓋 MWC59 基本產生器的統計缺陷,使得所有 59 位元都具有非常好的品質。
請注意,在處理值 V
時不要意外建立大數。
一般來說,使用此擾亂器的高位元比低位元好。請參閱此利基演算法 API 描述開頭的食譜。
對於小於約 29 位元的非 2 的冪次範圍(以避免過多偏差並避免大數),可以使用截斷乘法,這比使用 rem
快得多。例如,對於範圍 1'000'000'000;範圍為 30 位元,我們使用產生器的 29 位元,加起來為 59 位元,這不是大數(在 64 位元 VM 上):(1000000000 * (V bsr (59-29))) bsr 29
。
-spec splitmix64_next(AlgState :: integer()) -> {X :: uint64(), NewAlgState :: splitmix64_state()}.
產生 SplitMix64 隨機 64 位整數和新的演算法狀態。
根據指定的 AlgState
,依照 SplitMix64 演算法產生一個 64 位元的隨機整數 X
和一個新的產生器狀態 NewAlgState
。
此產生器在 rand
模組中內部用於設定其他產生器的種子,因為它與其他產生器截然不同,這降低了建立意外錯誤種子的機率。