18c0693f

Задача 11 Произведение матриц


Постановка задачи: Найти произведение прямоугольных матриц A*B

Из того, что мы узнали ранее, следует, какой вид может иметь заголовок пользовательской функции, решающей эту задачу. Два входных параметра функции должны быть типа Variant. Этот же тип должен быть у возвращаемого функцией значения. Конечно, это не единственно возможное решение. Можно было бы иметь один входной параметр, используя спецификатор ParamArray. Такой способ был бы единственно возможным, если обобщить постановку и попытаться создать функцию, которая должна перемножать произвольное число матриц. Но при умножении двух матриц естественнее иметь и два соответствующих им параметра. Поэтому заголовок получился таким:

Function MultMatr(A As Variant, B As Variant) As Variant

Я хочу показать Вам, как написать общую функцию, достаточно широкого назначения. Ее можно будет вызывать в формулах над массивами рабочего листа, передавая ей в качестве фактических параметров A и B массивы рабочего листа (объекты Range). Но не только объекты Range, но и массивы констант будут допускаться в качестве одного или обоих аргументов. Результат работы функции будет записан в массив, выделенный в момент вызова формулы над массивами. Более того, я хочу, чтобы эту же функцию можно было вызывать в обычных функциях и процедурах VBA, передавая в момент вызова массивы VBA в качестве аргументов. Все это, естественно, утяжелит нашу функцию, но позволит мне обсудить отличия "обычных" и "пользовательских функций. С учетом этих замечаний наша функция выглядит так:

Public Function MultMatr(A As Variant, B As Variant) As Variant 'Умножение матриц. 'Эта функция может вызываться в формулах рабочего листа Excel. 'В этом случае входные параметры являются объектами Range. 'Функцию можно также вызывать в обычных VBA функциях и процедурах, 'передавая ей в качестве параметров массивы VBA.

Dim AB() As Variant Dim i As Integer, j As Integer, k As Integer Dim N As Integer, M As Integer, P As Integer, Q As Integer Dim Correct As Boolean Dim msg1 As String, msg2 As String Dim Elem As Variant Correct = True


'Определение размерностей матриц If TypeName(A) = "Range" Then N = A.Rows.Count: M = A.Columns.Count ElseIf TypeName(A) = "Variant()" Then N = UBound(A, 1): M = UBound(A, 2) Else: Correct = False End If If TypeName(B) = "Range" Then P = B.Rows.Count: Q = B.Columns.Count ElseIf TypeName(A) = "Variant()" Then P = UBound(B, 1): Q = UBound(B, 2) Else: Correct = False End If ' Проверка корректности задания размерности If Correct And (P = M) Then 'Размерность задана корректно ReDim AB(1 To N, 1 To Q) 'Построение произведения матриц AB =A*B For i = 1 To N For j = 1 To Q Elem = 0 For k = 1 To M Elem = Elem + A(i, k) * B(k, j) Next k AB(i, j) = Elem Next j Next i MultMatr = AB Else 'Некорректно заданы аргументы или размерность If Not Correct Then msg2 = " При вызове MultMatr некорректно заданы аргументы!" _ & vbCrLf & "По крайней мере, один из них не является" _ & vbCrLf & "ни массивом, ни объектом Range" MsgBox (msg2) Else msg1 = " При вызове MultMatr некорректно задана размерность" _ & " перемножаемых матриц!" & vbCrLf & _ "Число столбцов в первом сомножителе = " & M & vbCrLf & _ "Число строк второго сомножителя = " & P MsgBox (msg1) End If End If End Function
Сделаем несколько замечаний.

Взгляните, как выглядят результаты некоторых экспериментов по умножению матриц на рабочем листе Excel:

увеличить изображение
Рис. 2.7.  Умножение матриц
На рабочем листе я расположил три матрицы разной размерности и дал им имена MatrA, MatrB и MatrC соответственно. Затем, вызывая MultMatr, я получил произведения MatrA*MatrB и MatrB*MatrC, - все выполнилось корректно. Попытка использовать MultMatr для умножения массива констант на матрицу - {1,2; 2,3}*MatrC закончилась неуспехом, поскольку, как я говорил ранее, для массивов констант некорректно работает функция Ubound. При попытке умножения MatrA*MatrC, как и положено, выдалось предупреждающее сообщение о несоблюдении правила размерности перемножаемых матриц.



Все публикации раздела