[英]Function Returns #Value Error sometimes
此方法基於以下3個步驟算法:
1-在[-1,1]間隔上生成兩個統一數字,您將分別稱為U1和U2
2-計算S = U1 ^ 2 + U2 ^ 2
3-如果S <1,則正常數字為U1 *平方根(-2 ln(S)/ S),否則返回步驟1,直到S <1。
在VB中對該函數進行編程,並將其命名為BoxMuller。
這是我根據上述步驟編寫的函數,我不確定它是否正確,因為有時它會返回#Value錯誤
我將以下值傳遞給函數=BoxMuller(Rand(),Rand())
Function BoxMuller(U1 As Double, U2 As Double) As Double
Dim S As Double
Do
U1 = WorksheetFunction.NormInv(U1, 0, 1)
U2 = WorksheetFunction.NormInv(U2, 0, 1)
S = U1 * U1 + U2 * U2
If S < 1 Then
BoxMuller = U1 * Sqr(-2 * Log(S) / S)
Exit Function
End If
Loop Until S < 1
End Function
是Loop Until S < 1
條件的Loop Until S < 1
因為我認為這可能是導致錯誤的真正原因。
還嘗試了以下方法:
Function BoxMuller() As Double
Dim S As Double
Dim U1 As Double
Dim U2 As Double
Do
U1 = WorksheetFunction.RandBetween(-1, 1)
U2 = WorksheetFunction.RandBetween(-1, 1)
S = U1 * U1 + U2 * U2
If S < 1 Then
BoxMuller = U1 * Sqr(-2 * Log(S) / S)
Exit Function
End If
Loop
End Function
並稱為=BoxMuller()
仍然#Value錯誤
KS Sheon工作流程正確
但
WorksheetFunction.RandBetween(-1,1)返回-1和1之間的整數
而VBA Rnd()函數返回0到1之間的隨機雙精度
我發布了兩個解決方案(BoxMuller1和BoxMuller2),以及上面的解決方案,它們僅在編碼樣式上有所不同,並且都使用遞歸調用
Function BoxMuller1(mu As Double, sigma As Double) As Double
Application.Volatile
Dim U1 As Double, U2 As Double, S As Double
Do While GetS(Rnd, Rnd, U1, U2, S) >=1
Randomize
Loop
BoxMuller1 = U1 * Sqr(-2 * Log(S) / S) * sigma + mu
End Function
Function GetS(Rnd1 As Double, Rnd2 As Double, U1 As Double, U2 As Double, S As Double) As Double
U1 = 2*Rnd1 - 1
U2 = 2*Rnd2 - 1
S = U1 * U1 + U2 * U2
GetS = S
End Function
Function BoxMuller2(mu As Double, sigma As Double) As Double
Application.Volatile
Dim U1 As Double, U2 As Double, S As Double
Randomize
U1 = 2*Rnd -1
U2 = 2*Rnd -1
S = U1 * U1 + U2 * U2
If S >= 1 Then
BoxMuller2 = BoxMuller2(mu, sigma)
Else
BoxMuller2 = U1 * Sqr(-2 * Log(S) / S) * sigma + mu
End If
End Function
我對最終輸出進行了一些調整,輸出不是標准分布,而是樣本的分布,因此將sigma乘以mu。 否則,該函數將不需要任何輸入。
Rnd
是生成隨機數的本地VBA,它始終在(0,1)范圍內。
您可以使用GoTo
而不是執行do...loop
,而不必調用exit function
來結束循環。
application.volatile
將確保每次按F9鍵時函數都會重新計算。 如果沒有,請刪除它。
Function BoxMuller(mu As Double, sigma As Double) As Double
Application.Volatile
Dim U1 As Double, U2 As Double, S As Double
ReCalc:
Randomize
'U1 = Rnd 'this is not correct for the function, leaving it here for reference.
'U2 = Rnd
'U1 = WorksheetFunction.RandBetween(-1, 1) 'this is wrong too, RandBetween only returns interger
'U2 = WorksheetFunction.RandBetween(-1, 1)
U1 = Rnd * 2 - 1
U2 = Rnd 'the BoxMuller formula don't require U2 to be negative.
S = U1 * U1 + U2 * U2
If S < 1 Then
BoxMuller = U1 * Sqr(-2 * (Log(S) / S) * sigma + mu
Else
GoTo ReCalc
End If
End Function
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.