我得到了这个VBA代码中的错误“types不匹配:数组或预期的用户定义的types”

我在名为NLRegress的子程序中遇到错误。 我认为在Sub NLRegress中的第一个调用中,数组types是不一样的。 Zmatrix是下列数组[1,0.2,0.04:1,0.5,0.25:1,0.8,0.64:1,1.2,1.44:1,1.7,2.89:1,2,4]

这是我的代码:

Option Explicit Option Base 1 Sub Main() Dim x() As Double, y() As Double, n As Integer, p As Integer, _ a() As Double, syx As Double, r2 As Double, m As Integer, _ yf() As Double, Z() As Double Dim i As Integer, k As Integer For k = 1 To 100 If Worksheets("Sheet1").Range("A2").Cells(k, 1).Value <> "" Then n = n + 1 'counts the number of data points Else Exit For End If Next k For k = 1 To 100 If Worksheets("Sheet1").Range("B2").Cells(k, 1).Value <> "" Then p = p + 1 'counts the number of data points Else Exit For End If Next k If p = n Then p = n ReDim yf(n) Else: MsgBox ("Unequal number of x and y values") End If ReDim x(n) ReDim y(n) For i = 1 To n 'Read data for matrix x x(i) = _ Worksheets("Sheet1").Range("A2").Cells(i, 1).Value Next For i = 1 To n 'Read data for matrix y y(i) = _ Worksheets("Sheet1").Range("B2").Cells(i, 1).Value Next m = Worksheets("Sheet1").Range("E2").Value ReDim a(m + 1) Call BuildZP(x, Z, n, m) Call NLRegress(Z, y, a, n, m) Call MultiplyMatrixByVector(Z, a, yf) End Sub Sub Fitted_Data(yf, a, x, n) Dim q As Integer For q = 1 To n yf(q) = a(1) + a(2) * x(q) + a(3) * x(q) ^ 2 Worksheets("Sheet1").Range("C2").Cells(q, 1).Value = yf(q) Next End Sub Sub NLRegress(Z, y, a, n, m) Dim er As Double, tol As Double, ZT() As Double, ZTZ() As Double, ZTZI() As Double, ZTY() As Double er = 0 tol = 0.0001 ReDim ZT(m + 1, n) Call TransposeMatrix(Z, ZT) Call MultiplyMatrices(ZT, Z, ZTZ) Call MatrixInverse(ZTZ, ZTZI, m + 1, tol, er) Call MultiplyMatrixByVector(ZT, y, ZTY) Call MultiplyMatrixByVector(ZTZI, ZTY, a) End Sub Sub BuildZP(x, Z, n, m) Dim i As Integer, j As Integer ReDim Z(n, m + 1) For i = 1 To n For j = 1 To m + 1 Z(i, j) = x(i) ^ (j - 1) Next j Next i End Sub 

这个答案可能不会解决你的问题(请参阅我的评论) – 但是让我给你一些可能使VBA编程更容易的最佳实践,也许可以防止这样的错误 – 在你的下一个项目中。

尝试将以下内容整合到您的编程中

  1. 正确的缩进:每次使用编程结构时,都会包含另一个代码块 – 例如ForIfWhile ,将封装的代码块进一步缩进一层。 例如,你的前几行代码应该看起来像
    对于k = 1到100
        如果Worksheets(“Sheet1”)。Range(“A2”)。Cells(k,1).Value <>“”Then
             n = n + 1'统计数据点的数量
        其他
            退出
        万一
    下一个k
    
  2. 您已经在使用Option Explicit ,这非常棒。 但是,你也应该适当地Dim过程/函数调用中的每个variables – 例如Sub Fitted_Data(yf as Double, ...)
  3. 您在主程序中总共使用了12个variables。 这是一个非常强的指标,你的日常工作太多了! 最好把它分解成小的子例程,也许使用几个模块variables – 见下面的例子。
  4. variables名是绝对没有意义的 – 这使得你很难debugging – 外部人几乎不可能理解你的代码在做什么。
  5. AFAIK你的第一个25行“只”分配给数组两个范围,并检查这些是否是相同的大小。 使用语法x = StartRange.Resize(NumberOfRows).Cells可以用更less的代码实现这一点,而且执行起来要快得多。
    同样的事情会发现第一个空行 – 而不是循环,使用StartRange.End(xlDown) – 这将返回您最后一个非空行!
    另外,如果你想给一个范围指定一个数组,它也可以用另一种方法: StartRange.Resize(NumberOfRows) = x
  6. 硬编码Worksheets("Sheet1").Range("A2")将导致用户更改工作表结构时出现问题,例如重命名工作表或插入行/列。 更好地分配单元格A2和B2的名称,例如StartVector1 ,然后使用Range("StartVector1")访问它们。 更强大 – 而且你的代码不那么混乱
  7. “不要重复自己”( DRY )。 如果你看到自己做了两次相同的代码,就把它作为一个单独的过程 – 例如你的代码来计算数据点的数量
  8. 无需使用Call Sub(x, y)Sub x, y与VBA中的等价
  9. Excel函数也可以用在VBA中。 这对matrixfunction来说特别方便。 例如,转置一个数组,你可以使用下面的代码: transposedX = worksheetFunctions.Transpose(x)

这里是前几个代码结构

 Option Explicit Private mVec1() As Double 'Better give a better name representing the target content of variable Private mVec2() As Double 'I use m as a prefix to indicate module wide scoped variables Public Sub SubDoingSomething() 'Use a name that tells the reader what the sub does LoadVectors BuildZP Z, n, m 'use proper variable names here NLRegress Z, y, a, n, m 'and maybe use some more module wide variables that you don't need to pass MultiplyMatrixByVector Z, a, yf End Sub Private Sub LoadVectors() Dim count1 As Long, count2 As Long count1 = GetRowLength(Range("StartVector1")) count2 = GetRowLength(Range("StartVector2")) If count1 <> count2 Then MsgBox ("Unequal number of x and y values") End End If mVec1 = Range("StartVector1").Resize(count1).Cells mVec2 = Range("StartVector2").Resize(count2).Cells End Sub Private Function GetRowLenght(rng As Range) If rng.Offset(1) = "" Then GetRowLength = 1 Else GetRowLength = rng.End(xlDown).Row - rng.Row + 1 End If End Function