簡體   English   中英

函數有時返回#Value錯誤

[英]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之間的隨機雙精度

  • VBA Log()函數實際上返回自然對數

我發布了兩個解決方案(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM