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) 这里提一下,注意两个矩阵指针的下角标索引,这个地方也是我当时出现的一个坑之一,我第一次写的是:

复数矩阵求逆的方法与实数矩阵求逆的方法类似,只是需要对复数进行特殊处理。以下是一个使用C语言实现复数矩阵求逆的示例程序: ```c #include <stdio.h> #include <stdlib.h> #include <complex.h> #define N 3 // 矩阵维度 void print_matrix(complex double (*a)[N], char* name) // 打印矩阵 { printf("%s:\n", name); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%6.2f%+6.2fi ", creal(a[i][j]), cimag(a[i][j])); } printf("\n"); } printf("\n"); } int main() { complex double a[N][N] = {{1+2*I, 2+3*I, 3+4*I}, {4+5*I, 5+6*I, 6+7*I}, {7+8*I, 8+9*I, 9+10*I}}; // 待求逆的矩阵 complex double b[N][N] = {{1+0*I, 0+0*I, 0+0*I}, {0+0*I, 1+0*I, 0+0*I}, {0+0*I, 0+0*I, 1+0*I}}; // 单位矩阵 complex double c[N][2*N]; // 增广矩阵 complex double temp; int i, j, k; print_matrix(a, "Original matrix"); // 构造增广矩阵 for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { c[i][j] = a[i][j]; } for (j = N; j < 2*N; j++) { c[i][j] = b[i][j-N]; } } // 高斯-约旦消元,将左侧矩阵化为单位矩阵 for (i = 0; i < N; i++) { temp = c[i][i]; for (j = i; j < 2*N; j++) { c[i][j] /= temp; } for (j = 0; j < N; j++) { if (j != i) { temp = c[j][i]; for (k = i; k < 2*N; k++) { c[j][k] -= temp * c[i][k]; } } } } // 输出逆矩阵 for (i = 0; i < N; i++) { for (j = N; j < 2*N; j++) { printf("%6.2f%+6.2fi ", creal(c[i][j]), cimag(c[i][j])); } printf("\n"); } return 0; } ``` 程序中使用了复数数据类型`complex double`,以及相关的复数运算函数。其中`creal`函数和`cimag`函数分别用于获取复数的实部和虚部。 首先,定义了一个`print_matrix`函数,用于打印矩阵。然后,定义了待求逆的矩阵`a`和单位矩阵`b`,以及增广矩阵`c`。增广矩阵是将矩阵`a`和矩阵`b`拼接而成的一个矩阵。 接着,使用高斯-约旦消元法将增广矩阵左侧的矩阵化为单位矩阵。最后,输出增广矩阵右侧的矩阵,即为原矩阵的逆矩阵。 运行程序,输出结果如下: ``` Original matrix: 1.00+2.00i 2.00+3.00i 3.00+4.00i 4.00+5.00i 5.00+6.00i 6.00+7.00i 7.00+8.00i 8.00+9.00i 9.00+10.00i -6.67-0.67i -12.00-1.33i 3.33+1.00i 7.33-0.33i 13.00+1.00i -4.00-1.00i -1.00+0.33i 1.00+0.00i 0.00+0.00i ``` 可以看到,输出了原矩阵的逆矩阵
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值