User defined function in VBA not “array-firendly”

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-25 08:07:04

问题


I have the following user-defined functions created:

Public Function LNt(LMiu As Double, LSigma As Double, t As Double)
Application.Volatile
LNt = Application.WorksheetFunction.NormDist(Log(t) / Log(2.71828182845905), LMiu, LSigma, False) / t
End Function

and

Public Function IntLNt(LMiu As Double, LSigma As Double, Lower As Double, Upper As Double, Step As Integer)
Application.Volatile

Dim Delta As Double
Dim I As Double

Delta = ((Log(Upper) / Log(2.71828182845905)) - (Log(Lower) / Log(2.71828182845905))) / Step

I = ((Log(Upper) / Log(2.71828182845905)) - (Log(Lower) / Log(2.71828182845905))) * (LNt(LMiu, LSigma, Lower) + LNt(LMiu, LSigma, Upper)) / (2 * Step)

For n = 2 To Step
I = I + LNt(LMiu, LSigma, Lower + Delta * (n - 1)) * Delta
Next

IntLNt = I
End Function

When I tried to run the formula in spreadsheet for various values of "Lower" and "Upper" (for summation through 1 to n), using

    =SUMPRODUCT(IntLNt(LMiu,LSigma,ROW(INDIRECT("1:8")),ROW(INDIRECT("1:8"))))

The result (when I evaluate the formula), does not return the values 1 through 8 within the array. It just returns the value 1.

Where is the mistake? Thanks for the help.


回答1:


Lets have an example of a UDF which can deal with arrays. This UDF takes two parameters. The first is x as a Double value. The other is a Variant. It can be either a single value or an array or a Range.

Public Function arrayFriendlyUDF(x As Double, vParam As Variant) As Variant
 'function which can get variant parameter vParam
 'either a single value or a range or an array literal
 'will return a single value or an array of results
 'it will only accept double values as single value, in range or in array literal

 Dim adParam As Variant, dParam As Double, aParam() As Double
 Dim aResult() As Double
 Dim i As Integer

 adParam = vParam
 'if vParam is a single value, then adParam also is a single value
 'if vParam is a range, then adParam is a variant array from this range's values
 'if vParam is a array literal, then adParam is a variant array from this array literal

 If TypeName(adParam) = "Variant()" Then 'we have a variant array
  'it could be one dimensional (row vector) or two dimensional (column vector)
  'we will only process one dimensional array, so we must transform if needed
  i = 0
  For Each vParam In adParam
   ReDim Preserve aParam(i)
   aParam(i) = vParam
   i = i + 1
  Next
 ElseIf TypeName(adParam) = "Double" Then 'we have a single double value
  ReDim aParam(0)
  aParam(0) = adParam
 End If
 'now we have an array (one dimensional) in any case

 For i = LBound(aParam) To UBound(aParam)
  ReDim Preserve aResult(i)

  aResult(i) = x * aParam(i) 'this is the function's operation. simply x * {vParam} in this case

 Next

 If UBound(aResult) = 0 Then
  'if only one result
  arrayFriendlyUDF = aResult(0)
 Else
  'return the array of results
  arrayFriendlyUDF = aResult
 End If

End Function

This UDF can be used as:

=arrayFriendlyUDF(2,3) result = 6

=arrayFriendlyUDF(2,A3) result = 6 if A3 contains 3

=SUM(arrayFriendlyUDF(2,{1;2;3;4})) result = 20 = sum n=1 to 4 (2 * n)

=SUM(arrayFriendlyUDF(2,A1:D1)) result = 20 if A1:D1 contains {1,2,3,4}

=SUM(arrayFriendlyUDF(2,A1:A4)) result = 20 if A1:A4 contains {1;2;3;4}

{=SUM(arrayFriendlyUDF(2,ROW(1:4)))} result = 20

{=SUM(arrayFriendlyUDF(2,COLUMN(A:D)))} result = 20

The last both formulas must be array formulas confirmed using Ctrl+Shift+Enter.


Still not clear with your UDF approach. As said in the comment your sample cell formula lacks the parameter Step which is not optional. And even if it would work as an array formula - what we could achieve now - the result would be an array of 0s always since Lower and Upper are always equal using ROW(INDIRECT("1:8")) for both.



来源:https://stackoverflow.com/questions/41792215/user-defined-function-in-vba-not-array-firendly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!