C语言实现实数和复数矩阵及其各种运算(三)

这篇博客详细讲解了C语言实现实数和复数矩阵的复制、转置、行列式、代数余子式和逆矩阵的运算。博主分享了函数实现及测试代码,特别强调了矩阵转置时的位置变换和共轭运算。同时,博主指出在编写这些函数时遇到的问题和陷阱,提醒读者注意。
摘要由CSDN通过智能技术生成

一、前言

  1. 本章开始,详细讲解实数和复数矩阵的转置复制行列式代数余子式等运算,由简入繁,并给出函数和测试demo的C代码,以及与matlab计算的结果;

  2. 并且,本章出现了我在编写函数、后期与matlab联调跑数据时候出现的几个坑,读者稍微留意一下。

 

 二、复制运算

复制运算,即对矩阵进行复制操作,将一个已知的矩阵原样赋值给另一个矩阵,且原矩阵内容不变:

/* Copy: Complex matrixA = Complex matrixB */
void CopyMatrix(const Matrix* matrix_A, Matrix* matrix_B)
{
	if (IsNullComplexMatrix(matrix_A))
	{
		puts("ERROE: An invalid matrix!\n");
		return;
	}
	//matrix_B->row = MatrixRow(matrix_A);
	//matrix_B->column = MatrixColumn(matrix_A);

	else
	{
		int index = 0;
		for (int row_i = 0; row_i < matrix_A->row; row_i++)
		{
			for (int column_j = 0; column_j < matrix_A->column; column_j++)
			{
				index = matrix_B->column * row_i + column_j;
				matrix_B->arrayComplex[index] = matrix_A->arrayComplex[index];
			}
		}	
		// OR:
		// memcpy(matrix_B->arrayComplex, matrix_A->arrayComplex, MatrixSize(matrix_A) * sizeof(ComplexType));
	}
}

说明

(1)  复制函数较为简单,关于测试的过程笔者就免去了;

(2)  同样对已知的矩阵matrix_A形参添加一个const限定符,然后在函数内部刚开始需要对该矩阵的存在性进行判断;

(3)  其实可以添加一个对被复制和赋值的矩阵matirx_B的行列数的判断,即确保两个矩阵最好size一样:

if( (MatrixRow(matirx_B) != MatrixRow(matrix_A)) ||(MatrixColumn(matrix_B) != MatrixColumn(matrix_A)) )
{
    DestroyComplexMatrix(&matirx_B);
    InitComplexMatrix(matrix_B, matrix_A.row, matrix_A.column);
}

(4)  这里也可以看到,对矩阵的索引有很多种不同的形式,可以是二维数学矩阵的形式,那就需要两个for循环语句,如果是以一维指针索引的形式,那就是一个for即可,另外考虑到角标冗长,建议读者定义一个局部变量来保存,或者直接用指针来遍历访问cell;

(5)  此外,接(4),因为矩阵元素全部用指针来索引,因此为了充分运用C语言库函数,直接使用memcpy()函数将矩阵整体赋值,完全不用使用for循环增加函数算法的时间复杂度,memcpy()函数包含在头文件string.h中,C++里是cstring,函数原型为:

void *memcpy(void *destin, void *source, unsigned n);

 

 三、转置运算

笔者这里重点讲解一下转置运算。

 

1.实数矩阵的转置

对于实数矩阵,转置即元胞位置作对称变换即可,即(i, j)--->(j, i)即可。这里我先给出实数矩阵的转置,比较简单:

/* Change Postion: [i, j] -- > [j, i] */
void TransPoseMatrix(const Matrix* matrixA, Matrix* matrixB)			// Tip:if A==U * U', then A'==A
{																		// So this function is not a necessity
	if (IsNullComplexMatrix(matrixA))
	{
		puts("ERROE: An invalid matrix!\n");
		return;
	}
	else if ((matrixA->row != matrixB->column) || (matrixA->column != matrixB->row))
	{
		puts("ERROE: An incompatable matrix!\n");
		return;
	}
	else
	{
		for (int row_i = 0; row_i < matrixA->row; row_i++)
		{
			for (int column_j = 0; column_j < matrixA->column; column_j++)
			{
				matrixB->arrayComplex[column_j * matrixB->column + row_i] = \
					matrixA->arrayComplex[row_i * matrixA->column + column_j];   // Attention!!!
			}
		}
	}
}

说明

其测试笔者这里省略,直接在下一节中可以得到验证。

2.复数矩阵的转置

对于复数矩阵,转置不仅是元胞位置做对称变换,还要对每个元胞作共轭运算,即(i, j)--->(j, i),且a+bj--->a-bj,code如下:

/* Conjugate Complex: Complex_B = creal(Complex_A) - cimag(Complpex_A) */
ComplexType ConjugateComplex(const ComplexType Complex_A)
{
	ComplexType Complex_B;
	Complex_B._Val[0] = creal(Complex_A);
	Complex_B._Val[1] = cimag(Complex_A) * (-1.0);
	return Complex_B;
}

/* Transposition: Complex matrixB = Complex matrixA' */
void TransMatrix(const Matrix* matrixA, Matrix* matrixB)			// matrixB is transposal matrix
{
	if (IsNullComplexMatrix(matrixA))
	{
		puts("ERROE: An invalid matrix!\n");
		return;
	}
	else if ( ( matrixA->row != matrixB->column) || (matrixA->column != matrixB->row) )
	{
		puts("ERROE: An incompatable matrix!\n");
		return;
	}
	else
	{
		for (int row_i = 0; row_i < matrixA->row; row_i++)
		{
			for (int column_j = 0; column_j < matrixA->column; column_j++)
			{
				// Transpose: position and sign w.r.t a Complex Number; only position w.r.t a Double Number
				matrixB->arrayComplex[column_j * matrixB->column + row_i] = \
					ConjugateComplex( matrixA->arrayComplex[row_i * matrixA->column + column_j] ); // Attention!!!
				// OR
/*
				matrixB->arrayComplex[column_j * matrixB->column + row_i]._Val[0] = \
					creal(matrixA->arrayComplex[row_i * matrixA->column + column_j]);   
				matrixB->arrayComplex[column_j * matrixB->column + row_i]._Val[1] = \
					cimag(matrixA->arrayComplex[row_i * matrixA->column + column_j]) * (-1.0);
*/
			}
		}
	}
}

说明

(1)  同样对矩阵的大小、存在性进行判断;

(2)  这里出现了新的嵌套调用的小函数,即第一个函数ConjugateComplex(),用于对一个复数作共轭运算,即虚部取反;

(3) 第二个函数对应于上一小节中的实数矩阵转置运算函数,唯一区别在于调用了共轭运算函数,将每个cell作共轭运算之后赋值给对应转置位置;

(4) 这里提一下,注意两个矩阵指针的下角标索引,这个地方也是我当时出现的一个坑之一,我第一次写的是:

为了读取一个二维复数矩阵(`mwArray`)并将其转换为两个单独的实部虚部矩阵(均为`double`类型),你可以使用MathWorks MATLAB C++ API。首先,你需要包括必要的头文件,并初始化`matlabengine`。以下是一个简单的示例代码: ```cpp #include "mat.h" #include "iostream" #include "stdexcept" void read_complex_matrix(const mwArray& complexMatrix, double* realMatrix, double* imagMatrix) { if (!complexMatrix.IsComplex()) { throw std::invalid_argument("输入的不是复数矩阵"); } int rows = complexMatrix.getNumberOfRows(); int cols = complexMatrix.getNumberOfColumns(); realMatrix = new double[rows * cols]; imagMatrix = new double[rows * cols]; for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { mwIndex index = i + j * rows; realMatrix[index] = complexMatrix(index).real; imagMatrix[index] = complexMatrix(index).imaginary; } } } // 示例如何读取矩阵并保存为.mat文件 int main() { try { // 初始化MATLAB引擎 mexAtexit(&mexShutdown); mexCallMATLAB(0, nullptr, 1, &yourMwArray, "read_complex_matrix", nullptr); double* realData = nullptr; double* imagData = nullptr; read_complex_matrix(yourMwArray, realData, imagData); // 创建一个新的矩阵(假设它们都是行向量) mxArray* realMat = mxCreateDoubleMatrix(rows, 1, mxREAL); mxArray* imagMat = mxCreateDoubleMatrix(rows, 1, mxREAL); // 将数据复制到新的矩阵中 memcpy(mxGetPr(realMat), realData, sizeof(double) * rows); memcpy(mxGetPr(imagMat), imagData, sizeof(double) * rows); // 保存为.mat文件 char filename[] = "output.mat"; mxArray* plhs[2] = {realMat, imagMat}; mexCallMATLAB(2, plhs, 0, nullptr, "save", {"filename", realMat, imagMat}); delete[] realData; delete[] imagData; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ``` 在这个例子中,我们首先从`yourMwArray`读取复数矩阵的数据,并将其拆分为实部虚部两个`double`数组。然后,创建两个`mxArray`来储存这两个数组的内容,并用`save`命令将它们保存为`.mat`文件。 请注意,`yourMwArray`应替换为你实际的二维复数矩阵,并确保你的环境中已经安装了MATLAB C++ API,并且可以在C++项目中正常使用。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值