2011-04-12 36 views
1

在某些迭代優化過程中,用於計算雙變量正態CDF的以下VBA代碼有時會在while循環內的z = hx * hy * c行上引發溢出錯誤上部功能。當乘法結果大於double可容納的值時,忽略溢出錯誤

我調試了代碼,當乘數相乘的數字大於double可以容納的數字時,就會發生溢出。

你能告訴我如何處理這個問題嗎?忽略這個高值的循環迭代 - 我想這是唯一可行的解​​決方案(?)。我在乘法之前用On Error Goto nextiteration行嘗試自己,並在Wend之前放置下一個跳躍點,但錯誤仍然存​​在。

Function tetrachoric(x As Double, y As Double, rho As Double) As Double 
    Const FACCURACY As Double = 0.0000000000001 
    Const MinStopK As Integer = 20 
    Dim k As Integer 
    Dim c As Double 
    Dim z As Double 
    Dim s As Double 
    Dim hx As Double 
    Dim hx1 As Double 
    Dim hx2 As Double 
    Dim hy As Double 
    Dim hy1 As Double 
    Dim hy2 As Double 
    Dim CheckPass As Integer 

    hx = 1 
    hy = 1 
    hx1 = 0 
    hy1 = 0 
    k = 0 

    c = rho 
    z = c 
    s = z 
    CheckPass = 0 

    While CheckPass < MinStopK 
     k = k + 1 
     hx2 = hx1 
     hy2 = hy1 
     hx1 = hx 
     hy1 = hy 
     hx = x * hx1 - (k - 1) * hx2 
     hy = y * hy1 - (k - 1) * hy2 
     c = c * rho/(k + 1) 
     z = hx * hy * c 
     s = s + z 
     If Abs(z/s) < FACCURACY Then 
      CheckPass = CheckPass + 1 
     Else 
      CheckPass = 0 
     End If 
    Wend 
    tetrachoric = s 
End Function 


Public Function bivnor(x As Double, y As Double, rho As Double) As Double 
' 
' bivnor function 
' Calculates bivariat normal CDF F(x,y,rho) for a pair of standard normal 
' random variables with correlation RHO 
' 
If rho = 0 Then 
    bivnor = Application.WorksheetFunction.NormSDist(x) * _ 
     Application.WorksheetFunction.NormSDist(y) 
Else 
    bivnor = Application.WorksheetFunction.NormSDist(x) * _ 
     Application.WorksheetFunction.NormSDist(y) + _ 
     Application.WorksheetFunction.NormDist(x, 0, 1, False) * _ 
     Application.WorksheetFunction.NormDist(y, 0, 1, False) * _ 
     tetrachoric(x, y, rho) 
End If 
End Function 

來源:可供下載http://michael.marginalq.com/

回答

1

更新代碼中使用On Error Resume Next代替On Error Goto

While CheckPass < MinStopK 
    k = k + 1 
    hx2 = hx1 
    hy2 = hy1 
    hx1 = hx 
    hy1 = hy 
    hx = x * hx1 - (k - 1) * hx2 
    hy = y * hy1 - (k - 1) * hy2 
    c = c * rho/(k + 1) 
    On Error Resume Next 
    z = hx * hy * c 
    If Err.Number = 0 Then 
     s = s + z 
     If Abs(z/s) < FACCURACY Then 
      CheckPass = CheckPass + 1 
     Else 
      CheckPass = 0 
     End If 
    Else 
     Err.Clear 
    End If 
Wend 
+0

剛剛嘗試過,並且與我自己的嘗試完全相同(除了「On Error Goto 0」之外的確與您的嘗試類似),溢出錯誤仍然存​​在。任何其他想法? – Steve06 2011-04-12 20:31:24

+0

如果你在'z = hx * hy * c'之前的行上放了一個'Debug.Print hx,hy,c',當你得到這個溢出時,這三個變量的值是多少?雙打的限制是非常難以擊中的。 – mwolfe02 2011-04-12 20:52:24

+0

我剛剛發佈的更新代碼運行時沒有生成錯誤消息,但似乎在溢出情況下輸出了'-1。#IND'(不確定)作爲結果值。這可能是一種致命的缺陷,你必須在@弗拉季斯拉夫的答案中探索選項。 – mwolfe02 2011-04-12 21:34:22

2

你打的計算機體系結構的限制。由於性能原因和/或溢出時的錯誤行爲,許多複雜算法無法以1:1的數學表示形式實現。有關於這些問題的特別好的博客 - John D. Cook

請看看here以獲得更好的實施。

你也可以嘗試綁定一個外部庫,它可以給你任意的精確數字處理,當然使用非常昂貴的(CPU時間方面)軟件算法來實現。更多可以找到here

+0

哈哈,在發佈之前我已經知道了西方文章(來自Wilmott雜誌發表的文章),事實上我已經使用了他的代碼,可以從他的網站上找到它。我只是想要另一種算法來交叉檢查結果,這就是爲什麼我按照Wiley Finance(Gunter Loeffler - VBA中的信用風險建模)書中推薦的方式嘗試上述代碼的原因。 – Steve06 2011-04-13 00:59:47

+0

約翰庫克的博客很棒。你也可以通過瀏覽他的stackoverflow的答案學到很多:http://stackoverflow.com/users/25188/john-d-cook – jtolle 2011-04-13 19:30:57

+0

哇,不知道他是在這麼:)謝謝jtolle! – 2011-04-13 19:36:06

1

http://www.codeproject.com/KB/recipes/float_point.aspx對待如何「使用對數來避免溢出和下溢」,這是一種簡單但非常有效的解決溢出問題的方法。事實上,它非常簡單而合乎邏輯,爲什麼我們自己沒有想到這個解決方案呢? ;)

+0

我覺得很愚蠢......約翰庫克讓我覺得很愚蠢! – 2011-04-14 07:04:05