演算法實現/偽隨機數/Wichmann-Hill (1982) PRNG
外觀
Visual Basic
[編輯 | 編輯原始碼]該演算法的行為與內建的 VBA Rnd() 函式非常相似,這可能並不奇怪,因為它是 Excel Rand() 函式相當長一段時間的基礎。這裡給出了一個簡短的總結
- Randomize() 函式用於設定位於模組級別的工作變數。這些變數在每個階段都用於計算 RndX() 輸出,並重新計算它們自己的值,為下次 RndX() 呼叫做好準備。
- RandomizeX() 在沒有引數的情況下呼叫時,使用來自系統計時器的輸入來設定變數。當給出引數時,生成的字元輸出流將對於該引數是不同的且可重複的。後一種情況適用於沒有為 RndX() 提供引數,或者在提供引數的情況下,只要它是一個正數。
- 最常見的配置,也是最有用的一種配置,是在 RndX() 之前呼叫 RandomizeX(),兩者都沒有引數。但是,如果程式碼中沒有包含 RandomizeX(),RndX() 在啟動時使用的工作變數預設值會導致相應的預設字元輸出流。每次在不首先呼叫 RandomizeX() 的情況下執行 RndX() 時,都會重複此流。
- 為 RndX() 新增正引數不會播種生成過程。除了 RndX() 的啟動預設值之外,所有播種都直接或間接地依賴於程式碼中是否包含 RandomizeX()。
- 請參閱下面的下拉框,以獲取引數設定及其結果的完整表格。
Option Explicit
Dim nX As Long, nY As Long, nZ As Long
Sub TestRndX()
Dim n As Long
RandomizeX
For n = 1 To 1000
'Debug.Print RndX()
MsgBox RndX()
Next n
End Sub
Sub RandomizeX(Optional ByVal nSeed As Variant)
'sets variables for PRNG procedure RndX()
Const MaxLong As Double = 2 ^ 31 - 1
Dim nS As Long
Dim nN As Double
'make multiplier
If IsMissing(nSeed) Then
nS = Timer * 60
Else
nN = Abs(Int(Val(nSeed)))
If nN > MaxLong Then 'no overflow
nN = nN - Int(nN / MaxLong) * MaxLong
End If
nS = nN
End If
'update variables
nX = (nS Mod 30269)
nY = (nS Mod 30307)
nZ = (nS Mod 30323)
'avoid zero state
If nX = 0 Then nX = 171
If nY = 0 Then nY = 172
If nZ = 0 Then nZ = 170
End Sub
Function RndX(Optional ByVal nSeed As Long = 1) As Double
'PRNG - gets pseudo random number - use with RandomizeX
'Wichmann-Hill algorithm of 1982
Dim nResult As Double
'initialize variables
If nX = 0 Then
nX = 171
nY = 172
nZ = 170
End If
'first update variables
If nSeed <> 0 Then
If nSeed < 0 Then RandomizeX (nSeed)
nX = (171 * nX) Mod 30269
nY = (172 * nY) Mod 30307
nZ = (170 * nZ) Mod 30323
End If
'use variables to calculate output
nResult = nX / 30269# + nY / 30307# + nZ / 30323#
RndX = nResult - Int(nResult)
End Function
- Wichmann, Brian; Hill, David (1982), Algorithm AS183: An Efficient and Portable Pseudo-Random Number Generator, Journal of the Royal Statistical Society. Series C
