2015-06-15 5 views
1

Я пытаюсь написать функцию в Excel для вычисления вероятности по умолчанию. У меня есть таблица с тремя столбцами данных. Я хочу, чтобы иметь возможность выделить выбор данных, и функция возвращает значение, основанное на данных, которые я выделил.Ошибка ссылки в VBA?

Функция считывает данные из электронной таблицы и затем выполняет итеративную процедуру (метод Ньютона) с использованием данных. Я пытаюсь сделать код ссылкой на первую строку выбора данных в электронной таблице, для первого «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 
+1

equity (i) где это определено? – 99moorem

+0

извините, я вышел из более ранней части кода, где это определенно: Option Explicit Private Const MMAX = 10000 общественной зрелости Как двойного частного капитала (от 1 до MMAX) As Double долга частного сектора (от 1 до MMAX) Как Double Private riskFree (1 to mMax) As Double Частный iptr As Integer Public sigmaAssetLast As Double – beeba

+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 в вашей функции.

+0

Эй это прекрасно работает! Большое вам спасибо, я застрял на этом несколько дней. Я очень ценю вашу помощь. – beeba

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 

Смотрите другой мой ответ о том, как изменить функцию, чтобы подтвердить выбор в качестве аргумента.

Также ваша функция может быть объявлена ​​частной, если вы хотите избежать использования функции в качестве формулы на листе.

Private Function VarunModel(ByVal Table As Range, ByVal SelectedRange As Range, Optional ByVal EndCondition As Integer = 0) As Variant 
Смежные вопросы