RTKLIB——matmul(矩阵乘法函数)

这篇具有很好参考价值的文章主要介绍了RTKLIB——matmul(矩阵乘法函数)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

RTKLIB——matmul(矩阵乘法函数)

笔者个人喜欢使用malloc开辟二维矩阵进行计算,在C语言线性代数专栏中对C语言中实验矩阵乘积、转置、求行列式、求逆等方法进行了详细的介绍。
RTKLIB中矩阵乘积函数matmul提供了另一种非常棒的思路,更加高效、便捷,且能够保证相对程度上的精度,以下是对matmul函数的介绍:

matmul是用来进行矩阵乘法的函数,其中传入参数如下:

判断是否需要转置标志:tr,“NN”(case 1)、“NT”(case 2)、“TN”(case 3)、“TT”(case 4),其中,T为需要转置、N为不需要转置

A矩阵的行:n

B矩阵的列:k

A矩阵的行=B矩阵的列:m

A*B精度缩放因子:alpha

C矩阵缩放因子:beta

ABC分别代表左矩阵A,右矩阵C,结果矩阵/原矩阵

/* multiply matrix -----------------------------------------------------------*/
extern void matmul(const char *tr, int n, int k, int m, double alpha,
                   const double *A, const double *B, double beta, double *C)
{
    double d;
    int i,j,x,f=tr[0]=='N'?(tr[1]=='N'?1:2):(tr[1]=='N'?3:4);
    
    for (i=0;i<n;i++) 
    {
        for (j=0;j<k;j++) 
        {
            d=0.0;
            switch (f) 
            {
                case 1: 
                        for (x=0;x<m;x++) 
                        {
                            d+=A[i+x*n]*B[x+j*m]; 
                        }
                            break;
                case 2: 
                        for (x=0;x<m;x++) 
                        {
                            d+=A[i+x*n]*B[j+x*k]; 
                        }
                            break;
                case 3: 
                        for (x=0;x<m;x++) 
                        {
                            d+=A[x+i*m]*B[x+j*m]; 
                        }
                            break;
                case 4: 
                        for (x=0;x<m;x++) 
                        {
                             d+=A[x+i*m]*B[j+x*k]; 
                        }
                             break;
            }
            if (beta==0.0) C[i+j*n]=alpha*d; else C[i+j*n]=alpha*d+beta*C[i+j*n];
        }
    }      
}

上述代码需要注意几点:

  • 矩阵A、B、C均是以一维数组形式来存储二维矩阵,假设A是i行j列的矩阵,A[i][x]的元素可用A[i+xn]表示
  • 代码中使用的是一维数组形式,因此传入参数可以是一维数组arr[9],也可以是动态内存开辟的数组 double* arr=(double*)malloc(sizeof(double)*9);
  • 代码中判定是否需要转置是根据“N”来判定,可依据自己需求加入大小写判断等
  • switch语句中务必加入break语句,若采用更严谨的写法,可加入default判断
  • alphabeta分别为矩阵AB乘积的缩放因子和C的缩放因子
  • 代码中存储数据是以列优先进行存储

什么是列优先

通常来讲,C语言中存储矩阵是以行优先的形式进行存储的。

例如下面3*3的矩阵,在C语言中可以使用如下方法:arr[3][3]={1,2,3,4,5,6,7,8,9},如果采用一维数组存储下面矩阵,通常会想到arr[9]={1,2,3,4,5,6,7,8,9},
然而riklib中并不是这样的!!!

rtklib中采用列主元的方式进行存储,也就是arr[9]={1,4,7,2,5,6,3,6,9},这种存储方式与Fortran中矩阵存储的形式相同(如果学过Fortran的同学都知道,列优先存储时逻辑上会更加清晰)

[ 1 2 3 4 5 6 7 8 9 ] \left[ \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{matrix} \right] 147258369

搞懂列优先后,再看rktlib中矩阵运算规则就一目了然了。


为什么要对矩阵进行缩放?

在矩阵乘法中,如果乘积结果的值非常大或非常小,那么在计算机中表示这个值可能会导致精度损失或溢出。因此,在矩阵乘法中,常常需要对结果进行缩放,以保持数值的合适范围,同时尽可能地保留精度。

缩放的方法通常是对结果矩阵中的每个元素都乘以一个常数因子,这个常数因子通常被称为缩放因子或比例因子。上述代码中,如果 beta 等于 0,表示不需要对原矩阵C进行缩放,只需乘对乘积结果乘以一个常数因子 alpha;如果 beta 不等于 0,则需要将原有的结果矩阵 C 乘以一个常数因子 beta,再加上新计算出的结果矩阵 alpha*d,以获得最终的结果矩阵 C。

下面是使用matmul的简单示例:

void Test()
{
	double arr1[]={1,1,2,2,3,3};//row=3,col=2
	double arr2[]={1,1,1,1,1,1};//row=2,col=3
	double* arr=(double*)malloc(sizeof(double)*9);
    memset(arr,0,sizeof(double)*9);
	matmul("NN",3, 3, 2, 1.0,arr1,arr2,0.0,arr);
	for(i=0;i<3;i++)
	{
		for(j=0;j<3;j++)
		{
			printf("%2.0lf\t",arr[i+j*3]);
		}
		putchar('\n');
	}
}

其中:matmul("NN",3, 3, 2, 1.0,arr1,arr2,0.0,arr);表示矩阵AB不需要转置,其中A为3行2列,B为2行3列,AB乘积的缩放因子为1.0(不需要缩放),C的缩放因子因子为0,表示不需要对C进行缩放。

注意:因为有缩放因子的存在,如果原矩阵C为空,需要将其初始化。


个人改进方法

RTKLIB中的乘法函数采用一维数组表达二维矩阵,提高了开辟内存时的效率与访问速度,但也因此会有以下几个问题:

1)赋值时需要以列优先原则赋值,代码可读性较差

2)传入参数必须手动输入矩阵的行列、容易造成人工输入bug

以下是笔者比较喜爱的一种运算方式,如果数据量不是非常庞大,下面代码更好理解与方便:

1)创建了Matrix结构体,用于存储矩阵信息(如果是Winodows系统,可以使用_msize函数访问内存进行维数判定,那么就需要专门创建结构体存储信息了,但是该方法Mac/Linux不适用)

2)加入了几个暴力检查,主要针对输入错误

3)代码可读性高,代码中存储数值的逻辑符合正常逻辑

但是需要注意以下几点:

1)MakeMatrix创建矩阵的逻辑为一列一列循环创建,因此要释放内存时,需要使用free_Matrix依次循环释放内存

2)手动赋值时较为麻烦

3)内存管理不如上述方式文章来源地址https://www.toymoban.com/news/detail-621617.html

//矩阵结构体声明
typedef struct Matrix
{
	int row;
	int col;
	double** data;
}Matrix,*pMatrix;
//循环释放内存函数
void free_Matrix(Matrix arr)
{
	int i;
	for (i = 0; i < arr.row; i++)
	{
		free(arr.data[i]);
	}
}
//创建矩阵函数
Matrix MakeMatrix(int row, int col)
{
	int i = 0;
	Matrix arr = {0};
	arr.row = row;
	arr.col = col;
	arr.data = (double **)malloc(sizeof(double *) * arr.row);
	if (arr.data == NULL)
		exit(-1);
	for (i = 0; i < arr.row; i++)
	{
		arr.data[i] = (double *)malloc(sizeof(double) * arr.col);
		memset(arr.data[i], 0, sizeof(double) * arr.col);
	}
	return arr;
}
//打印矩阵函数
void PrintMatrix(Matrix arr)
{
	int i, j;
	for (i = 0; i < arr.row; i++)
	{
		for (j = 0; j < arr.col; j++)
		{
			printf("%lf\t", arr.data[i][j]);
		}
		putchar('\n');
	}
}
//利用Matrix结构体实现matmul矩阵乘法
extern void matmul2(const char *tr, const Matrix A, const Matrix B, const Matrix C, double alpha, double beta)
{
	double d;
	int i, j, x, f, row, col, k;
	f = tr[0] == 'N' ? (tr[1] == 'N' ? 1 : 2) : (tr[1] == 'N' ? 3 : 4);
	//这里对比一下就能看出来RTKLIB中的精妙之处,因为函数采用二维矩阵的形式,因此在计算前要根据转置情况重新判断行列情况。
	row = A.row, col = B.col, k = A.col;
	if (f == 2)
		col = B.row;
	else if (f == 3)
	{
		row = A.col;
		k = A.row;
	}
	else if (f == 4)
	{
		row = A.col;
		col = B.row;
		k = A.row;
	}

	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			d = 0.0;
			switch (f)
			{
			case 1:
				for (x = 0; x < k; x++)
				{
					d += A.data[i][x] * B.data[x][j];
				}
				break;
			case 2:
				for (x = 0; x < k; x++)
				{
					d += A.data[i][x] * B.data[j][x];
				}
				break;
			case 3:
				for (x = 0; x < k; x++)
				{
					d += A.data[x][i] * B.data[x][j];
				}
				break;
			case 4:
				for (x = 0; x < k; x++)
				{
					d += A.data[x][i] * B.data[j][x];
				}
				break;
			}
			if (beta == 0.0)
				C.data[i][j] = alpha * d;
			else
				C.data[i][j] = alpha * d + beta * C.data[i][j];
		}
	}
}

到了这里,关于RTKLIB——matmul(矩阵乘法函数)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 线性代数:矩阵运算(加减、数乘、乘法、幂、除、转置)

    目录 加减 数乘  矩阵与矩阵相乘  矩阵的幂 矩阵转置  方阵的行列式  方阵的行列式,证明:|AB| = |A| |B|        

    2024年01月22日
    浏览(51)
  • 线性代数本质系列(二)矩阵乘法与复合线性变换,行列式,三维空间线性变换

    本系列文章将从下面不同角度解析线性代数的本质,本文是本系列第二篇 向量究竟是什么? 向量的线性组合,基与线性相关 矩阵与线性相关 矩阵乘法与复合线性变换 三维空间中的线性变换 行列式 逆矩阵,列空间,秩与零空间 克莱姆法则 非方阵 点积与对偶性 叉积 以线性

    2024年02月02日
    浏览(54)
  • 【线性代数】通过矩阵乘法得到的线性方程组和原来的线性方程组同解吗?

    如果你进行的矩阵乘法涉及一个线性方程组 Ax = b,并且你乘以一个可逆矩阵 M,且产生新的方程组 M(Ax) = Mb,那么这两个系统是等价的;它们具有相同的解集。这是因为可逆矩阵的乘法可以视为一个可逆的线性变换,不会改变方程解的存在性或唯一性。 换句话说,如果你将原

    2024年02月03日
    浏览(61)
  • 线性代数矩阵乘法中的行向量和列向量

    在矩阵中有两个概念,行向量与列向量,这是从两个不同的角度看待矩阵的组成。这篇文章将从 行向量 和 列向量 两个角度来分解 矩阵的乘法 。 假设有两个矩阵 A 和 B 一般矩阵的乘法分解 简单的理解就是A矩阵的第一行与B矩阵的第一列逐元素相乘,就是 结果矩阵 的左上角

    2024年02月11日
    浏览(47)
  • <3>【深度学习 × PyTorch】必会 线性代数 (含详细分析):点积 | 矩阵-向量积 | Hadamard积 | 矩阵乘法 | 范数/矩阵范数

      拍照的意义在于你按下快门的那一刻,万里山河的一瞬间变成了永恒。   🎯作者主页: 追光者♂🔥          🌸个人简介:   💖[1] 计算机专业硕士研究生💖   🌟[2] 2022年度博客之星人工智能领域TOP4🌟   🏅[3] 阿里云社区特邀专家博主🏅   🏆[4] CSDN-人工智能领域

    2024年02月05日
    浏览(58)
  • 第一百二十一天学习记录:线性代数:矩阵乘法运算(宋浩板书)

    在编程和学习数据结构的过程中,发现有些算法会用到矩阵和矩阵的乘法运算,因此先将这一个知识点学习一下。 乘法☆ 总结三条不满足

    2024年02月13日
    浏览(42)
  • RTKLIB模糊度固定模式介绍以及部分模糊度固定技术(附源码,基于RTKLIB)

    伪距从名称上来看,其实是一个距离,虽然该“距离”含有误差以及随机噪声较大;但接收机在第一次跟踪载波时,只能明确知道其初始相位,在信号传播过程中的周期数是没有办法明确知道的,而这个周期数就是我们要确定的模糊度。 虽然伪距精度相对较低,但多历元滤波

    2024年02月05日
    浏览(132)
  • 1.RTKLIB环境配置和调试

    下载链接:rtklib 注:2.4.2 p13为稳定版本(标识p代表稳定版本),2.4.3 b34为最新实验版本(标识b)。点击2.4.3 b34 的Source Programs and Data 链接下载源码。 **集成开发环境:**Visual Studio 2022 项目路径:E:My_RTKLIBMy_RTKLIB 对下载的RTKLIB软件包中需要保留如下内容 (1)RTKLIB-rtklib_2.4.

    2024年02月10日
    浏览(34)
  • 线性代数的学习和整理13: 函数与向量/矩阵

    目录 1 函数与 向量/矩阵 2 初等数学的函数 2.1 函数 2.2 函数的定义:定义域  →映射→  值域 3  高等数学里的函数:定义域和陪域/到达域(非值域)的映射关系 3.1 函数 3.2 单射,满射,双射等都是针对定义域 和 陪域的 3.3 易错地方:值域较小且是被决定的 3.4 单射,满射,

    2024年02月11日
    浏览(66)
  • 线性代数的学习和整理14: 线性方程组求解的3种方法,重点讲矩阵函数求解

    目录 0 写在前面的一些内容 0.1 学习心得: 0.2 参考其他书籍总结的知识点,对照学习 1 线性方程组求解 1.1 常见的线性方程组如下 1.2 记住常见的 矩阵函数的维数的关系 1.3  需要求解的方程组和矩阵的对应关系,需要先厘清 1.3.1 如果只需要求解x,是类 Ax=b的形式 1.3.2   如

    2024年02月05日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包