【c++】以函数调用的方式来书写矩阵乘法
第一版
/*m:A的行 * o:A的列,B的行 * n:B的列 * res:存储最终的结果 */ void multi(double A0[21][21], double B0[21][21], int m, int o, int n, double res[21][21]) { double A[21][21]; double B[21][21]; double temp; //防止对原矩阵进行修改 for (int i = 0;i < 21;i++) { for (int j = 0;j < 21;j++) { A[i][j] = A0[i][j]; } } for (int i = 0;i < 21;i++) { for (int j = 0;j < 21;j++) { B[i][j] = B0[i][j]; } } for (int i = 0;i < m + 1;i++) { for (int j = 0;j < n + 1;j++) { temp = 0; for (int k = 0;k < o + 1;k++) { temp += A[i][k] * B[k][j]; } res[i][j] = temp; } } }
可以进一步修改:
point 1:创建二维数组
在平时创建二维数组时,不能省略列,但可以省略行,但是在矩阵乘法中,行和列的信息都要有。
point 2:二维数组传参
数组的数组名表示数组首元素的地址。二维数组的数组名表示数组第一行的地址。二维数组的首元素为数组第一行。
void test(double* arr) { //错误写法。 } void test(double** arr) { //错误写法。二级指针用来存放一级指针的地址,而不是数组第一行的地址 } void test(double* arr[2]) { //错误写法 } void test(double (*arr)[2]) {//正确写法 }
point 3:矩阵乘法
矩阵乘法只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义。这一部分可以将输入改为两个矩阵的行和列,然后使用assert进行检验。
point 4:对于数组函数参数,指针语法*优先于数组语法[]
对之前的矩阵乘法代码进行改良,得到下列代码:
#include <iostream> #include <assert.h> constexpr int row{ 2 }; constexpr int col{ 2 }; void multi(double (* A0)[col], double (* B0)[col], int row1, int col1, int row2, int col2, double (* res)[col]) { assert(col1 == row2); double temp; for (int i = 0;i != row1; ++i) { for (int j = 0;j != col2; ++j) { temp = 0; for (int k = 0;k != col1; ++k) { temp += *((*A0 + i) + k) * *((*B0 + k) + j); //temp += A0[i][k] * B0[k][j]; } res[i][j] = temp; } } }
point 5 std::vector
可以使用std::vector 创建二维数组。std::vector可以直接初始化,且可以初始化为非零元素。并且vector一般不用进行显式的释放;
#include <iostream> #include <assert.h> #include <vector> #include <algorithm> #include <array> using vec = std::vector<std::vector<double>>; using vecRow = std::vector<double>; vec Multi(vec& A, vec& B) { int row1 = A.size(); int col1 = A[0].size(); int row2 = B.size(); int col2 = B[0].size(); vec res; vecRow temp; double sum; //double temp; assert(col1 == row2 && "第一个矩阵的列和第二个矩阵的行不相等"); for (int i = 0;i != row1;++i) { for (int j = 0;j != col2;++j) { sum = 0; for (int k = 0;k != col1;++k) { sum += A[i][k] * B[k][j]; } temp.push_back(sum); } res.push_back(temp); temp.erase(temp.begin(), temp.end()); } return res; }
相应的main函数:
int main() { vec A{ {1.0, 1.0}, { 2.0,2.0 } }; vec B { {2.0, 2.0}, { 1.0,1.0 } }; vec res; res = Multi(A, B); show(res); }
也可以在使用vector的时候将矩阵res初始化为想要的大小。
vec multi(vec A, vec B) { int row1{ static_cast<int> (A.size()) }; int col1{ static_cast<int>(A[0].size()) }; int row2{ static_cast<int>(B.size()) }; int col2{ static_cast<int>(B[0].size() )}; vec res(row1, vecRow(col2)); double temp{}; assert(col1 == row2 && "第一个矩阵的列和第二个矩阵的行不相等"); for (int i = 0;i != row1;++i) { for (int j = 0;j != col2;++j) { temp = 0; for (int k = 0;k != col1;++k) { temp += A[i][k] * B[k][j]; } res[i][j] = temp; } } return res; }
在打印矩阵相乘的计算结果时,可以采用:
void show(vec& A) { for (vecRow i : A) { for (double j : i) { std::cout << j << " "; } std::cout << '\n'; } /* for (int i = 0;i != A.size();++i) { for (int j = 0;j != A[0].size();++j) { std::cout << A[i][j] << " "; } std::cout << "\n"; }*/ }