VBA中的循环引用错误?

时间:2015-06-15 14:04:49

标签: excel vba excel-vba

我试图在Excel中编写一个函数来计算默认概率。我有一个包含3列数据的电子表格。我希望能够突出显示一系列数据,并让函数返回一个基于我突出显示的数据的值。

该函数从电子表格中读取数据,然后使用数据执行迭代过程(牛顿方法)。我试图让代码引用电子表格中数据选择的第一行,对于第一个" i"。然后对于第二个i,我希望它引用第二行,依此类推。到目前为止,我已经得到了这个:

iNumRows = Table.Rows.Count

maturity = Worksheets("KMV-Merton").Range("B2").Value
For i = 1 To iNumRows
    equity(i) = SelectedRange.Cells("1").Offset(i - 1, 0).Value
    debt(i) = SelectedRange.Cells("2").Offset(i - 1, 0).Value
    riskFree(i) = SelectedRange.Cells("3").Offset(i - 1, 0).Value
Next i

但是这会导致电子表格上出现循环引用错误。我做错了什么?

完整代码如下,以防错误发生在其他地方。

Option Explicit
    Private Const mMax = 10000
    Public maturity As Double
    Private equity(1 To mMax) As Double
    Private debt(1 To mMax) As Double
    Private riskFree(1 To mMax) As Double
    Private iptr As Integer
    Public sigmaAssetLast As Double



Function VarunModel(Table As Range, Optional EndCondition As Integer = 0) As Variant
    Dim iNumCols As Integer, iNumRows As Integer
    Dim i As Integer

    Dim SelectedRange As Range
    Set SelectedRange = Selection

    iNumCols = Table.Columns.Count
    iNumRows = Table.Rows.Count

    maturity = Worksheets("KMV-Merton").Range("B2").Value
    For i = 1 To iNumRows
        equity(i) = SelectedRange.Cells("1").Offset(i - 1, 0).Value
        debt(i) = SelectedRange.Cells("2").Offset(i - 1, 0).Value
        riskFree(i) = SelectedRange.Cells("3").Offset(i - 1, 0).Value
    Next i

    Dim equityReturn As Variant: ReDim equityReturn(2 To iNumRows)
    Dim sigmaEquity As Double
    Dim asset() As Double: ReDim asset(1 To iNumRows)
    Dim assetReturn As Variant: ReDim assetReturn(2 To iNumRows)
    Dim sigmaAsset As Double, meanAsset As Double
    Dim x(1 To 1) As Double, n As Integer, prec As Double, precFlag As Boolean, maxDev As Double

    For i = 2 To iNumRows: equityReturn(i) = Log(equity(i) / equity(i - 1)): Next i
        sigmaEquity = WorksheetFunction.StDev(equityReturn) * Sqr(260)
        sigmaAsset = sigmaEquity * equity(iNumRows) / (equity(iNumRows) + debt(iNumRows))
    NextItr: sigmaAssetLast = sigmaAsset

    For iptr = 1 To iNumRows
        x(1) = equity(iptr) + debt(iptr)
        n = 1
        prec = 0.00000001
        Call NewtonRaphson(n, prec, x, precFlag, maxDev)
        asset(iptr) = x(1)
    Next iptr

    For i = 2 To iNumRows: assetReturn(i) = Log(asset(i) / asset(i - 1)): Next i

    sigmaAsset = WorksheetFunction.StDev(assetReturn) * Sqr(260)
    meanAsset = WorksheetFunction.Average(assetReturn) * 260
    If (Abs(sigmaAssetLast - sigmaAsset) > prec) Then GoTo NextItr

    Dim disToDef As Double: disToDef = (Log(asset(iNumRows) / debt(iNumRows)) + (meanAsset - sigmaAsset ^ 2 / 2) * maturity) / (sigmaAsset * Sqr(maturity))
    Dim defProb As Double: defProb = WorksheetFunction.NormSDist(-disToDef)

    VarunModel = defProb        
End Function

2 个答案:

答案 0 :(得分:0)

请勿在您的功能中使用Selection。使用它会导致单元格在工作表中输入公式的瞬间引用自身。这是您的循环参考。

您需要删除这两行。

Dim SelectedRange As Range
Set SelectedRange = Selection

相反,您需要将SelectedRange作为参数添加到公式中。

Function VarunModel(ByVal Table As Range, ByVal SelectedRange As Range, Optional ByVal EndCondition As Integer = 0) As Variant

然后在单元格中输入这样的公式。

=VarunModel(A3:C18,A5:C6)

第二个参数是您的“选定”范围。关键是它根本不再取决于选择。相反,您明确告诉它用于计算的范围。

这可能不是您想要的行为,但您需要避免在函数中使用Selection

答案 1 :(得分:0)

如果您真的想在代码中使用Selection,则需要创建一个Sub来调用您的函数。您需要在代码中指定输出范围。

在工作表上创建一个按钮以运行此代码:

Sub outputVarunValue()
    Dim Table As Range
    Dim OutputCell As Range

    'need range name "TableRange"
    Set Table = Worksheets("KMV-Merton").Range("TableRange")

    'need single cell with range name "OutputCell"
    Set OutputCell = Worksheets("KMV-Merton").Range("OutputCell")

    'use the Selection as an argument
    OutputCell.Value = VarunModel(Table, Selection)

End Sub

请参阅我的其他答案,了解如何修改函数以接受Selection作为参数。

如果你想避免在工作表上使用函数作为公式,你的函数也可以声明为Private。

Private Function VarunModel(ByVal Table As Range, ByVal SelectedRange As Range, Optional ByVal EndCondition As Integer = 0) As Variant