如何在工作表中使用单元格范围的UDF?

问题描述:

我想创建一个用户定义的函数,以便在Excel工作表中使用。我的函数使用三个单元格范围作为输入,并应返回一个单一的值作为结果。如此,它在结构上与例如SUMPRODUCT函数,只有执行的数学是不同的。如何在工作表中使用单元格范围的UDF?

这是我使用的代码:

Function MyFunction(C(), V(), M()) As Double 
    Application.Volatile (True) 

    Dim i As Long, j As Long, x As Long 
    Dim Sum_Phi_i As Double 

    x = UBound(C, 0) 

    MyFunction = 0 
    For i = 0 To x 
     Sum_Phi_i = 0 
     For j = 0 To x 
     Sum_Phi_i = Sum_Phi_i + C(j) * Sqr(2)/(4 * Sqr(1 + M(i)/M(j))) * (1 + Sqr(V(i)/V(j)) * (M(j)/M(i))^0.25)^2 
      Next j 
     MyFunction = MyFunction + C(i) * V(i)/Sum_Phi_i 
     Next i 

End Function 

我有这样做的问题是,它返回#VALUE!错误。显然,我错误地定义的数据类型,因为当我在工作表中,我得到使用此功能: A value used in the formula is of the wrong data type

我试图定义使用阵列C,M & V作为范围或双无济于事。我怎么解决这个问题?

除了这个问题,我也想知道如何确保选定的单元格区域具有相同的大小。我正在想办法:

x = UBound(C, 0) 
y = UBound(M, 0) 
z = UBound(M, 0) 

If x <> y Or x <> z Or y <> z Then MyFunction = "Arrays are not of same size" 
If x <> y Or x <> z Or y <> z Then Exit Function 

会这样吗?或者这会产生问题,因为输出将是一个字符串,而我将我的“MyFunction”定义为double?如果是这样,那么如何解决或有更好的方法来强制用户做出相同大小的范围选择?

请试试这个功能。它的测试,除了我已经添加括号的公式,但是,从乘法中分离加法,如Fun = Fun + (3 * 4)而不是Fun = Fun + 3 * 4

Function MyFunction(C As Range, _ 
        V As Range, _ 
        M As Range) As Double 
    ' 21 Oct 2017 

    Application.Volatile (True) 

    Dim Fun As Double      ' function return value 
    Dim ArrC, ArrV, ArrM 
    Dim i As Long, j As Long, x As Long 
    Dim PhiSum As Double 

    ArrC = C.Value 
    ArrV = V.Value 
    ArrM = M.Value 
    x = UBound(ArrC, 2) 

    If (UBound(ArrC) > 1) Or (UBound(ArrV) > 1) Or (UBound(ArrM) > 1) Then 
     MsgBox "Please specify horizontal ranges each" & vbCr & _ 
       "comprising a single row only.", vbExclamation, "Invalid parameter" 
     Exit Function 
    End If 

    If (UBound(ArrV, 2) <> x) Or (UBound(ArrM, 2) <> x) Then 
     MsgBox "Specified ranges must be of equal size.", _ 
       vbCritical, "Invalid parameter" 
     Exit Function 
    End If  

    For i = 1 To x 
     PhiSum = 0 
     For j = 1 To x 
      PhiSum = PhiSum + (ArrC(1, j) * Sqr(2) _ 
          /(4 * Sqr(1 + ArrM(1, i)) _ 
          /ArrM(1, j)) * (1 + Sqr(ArrV(1, i) _ 
          /ArrV(1, j)) * (ArrM(1, j) _ 
          /ArrM(1, i))^0.25)^2) 
     Next j 
     Fun = Fun + (ArrC(1, i) * ArrV(1, i)/PhiSum) 
    Next i 
    MyFunction = Fun 
End Function 
+0

感谢您的帮助。我现在得到了一个实际的结果(虽然不是正确的;我需要重新检查我的公式)。 – Enantiomeer

+0

我还在想,是否可以强制该函数只接受一维水平单元格范围(行)。 – Enantiomeer

+0

我修改了代码以包含多行选择的拒绝。实际上这并不是必需的,但是,因为代码只处理第一行。如果您的工作表的结构允许,让用户选择第一个范围并让代码找到其他范围会更好。如果其他两个连续行,这将是可能的。 – Variatus

编译,未经测试...

Function MyFunction(C As Range, V As Range, M As Range) As Double 

    Application.Volatile True 
    Dim i As Long, j As Long, x As Long 
    Dim Sum_Phi_i As Double 
    Dim vC, vV, vM 
    vC = C.Value 
    vV = V.Value 
    vM = M.Value 

    x = UBound(vC, 1) 'dimensions are 1 and 2 and lower bound of each=1 

    MyFunction = 0 
    For i = 1 To x 
     Sum_Phi_i = 0 
     For j = 1 To x 
      Sum_Phi_i = Sum_Phi_i + vC(j) * Sqr(2)/(4 * Sqr(1 + vM(i)/vM(j))) * _ 
         (1 + Sqr(vV(i)/vV(j)) * (vM(j)/vM(i))^0.25)^2 
     Next j 
     MyFunction = MyFunction + (vC(i) * vV(i)/Sum_Phi_i) 
    Next i 

End Function