[C语言]矩阵运算
最近要做一个MFC的上位机,用到CSP滤波算法,这玩意儿在MATLAB 里相当简单就能实现但C里面实现起来太蛋疼,写了一个晚上才把这个算法用到的矩阵运算部分的函数写的差不多,为了避免以后再重复造轮子,现在这里写一下备份一下吧。。
1.矩阵乘法
//矩阵乘法 /********参数表******* @Parameter x: m行k列矩阵(用一维数组表示) @Parameter y: k行n列矩阵(用一维数组表示) @Parameter m,k,n: 矩阵行列参数 @Parameter z: m行n列输出矩阵(用一维数组表示) ***********************/ void MulMatrixDD(double *x,double *y, int m,int k,int n, double *z) { for(int nm=0; nm<m; nm++) for(int nn=0; nn<n; nn++) for(int nk=0; nk<k; nk++) z[nm*n+nn] += x[nm*k+nk]*y[nk*n+nn]; }
因为输入的x,y可能是不同的类型(short, double)所以我只简单的复制了几个函数来表示,比如输入如果是x如果是short型,y是double型这个函数就不好用了。如果有什么更好的通用方法可以跟我交流下
2.方阵转置
//方阵转置 /********参数表******* @Parameter x: m行m列矩阵(用一维数组表示) @Parameter m: 矩阵行列数 ***********************/ void TransSquareD(double *x, int m) { double temp; for(int nm=0; nm<m; nm++){ //对原矩阵第nm行 for(int nn=0; nn<nm; nn++){ //对原矩阵第nn列 temp = x[nm*m+nn]; //z矩阵第nn行第nm列 x[nm*m+nn] = x[nn*m+nm]; x[nn*m+nm] = temp;}} }
3.非方阵转置
//非方阵转置 /********参数表******* @Parameter x: m行n列矩阵(用一维数组表示) @Parameter m,n: 矩阵行列数 @Parameter z: n行m列矩阵(用一维数组表示) ***********************/ void TransMatrixD(double *x, int m, int n, double *z) { for(int nm=0; nm<m; nm++) //对原矩阵第nm行 for(int nn=0; nn<n; nn++) //对原矩阵第nn列 z[nn*m+nm] = x[nm*n+nn]; //z矩阵第nn行第nm列 } void TransMatrixS(short *x, int m, int n, double *z) { for(int nm=0; nm<m; nm++) //对原矩阵第nm行 for(int nn=0; nn<n; nn++) //对原矩阵第nn列 z[nn*m+nm] = (double)x[nm*n+nn]; //z矩阵第nn行第nm列 }
4.协方差矩阵
//协方差矩阵函数 /********参数表******* @Parameter X[m_cov][n_cov]: m_cov行n_cov列矩阵(用二维数组表示) ***********************/ void CovMat(short X[m_cov][n_cov]) { for(int i=0; i<m_cov; i++) for(int j=0; j<m_cov; j++) CovMatrix[i][j] = cov(*(X+i),*(X+j)); } //协方差函数 double cov(short *x, short *y) { double sumx = 0; double sumy = 0; double sum = 0; int kk = 0; for(kk = 0; kk<n_cov; kk++) { sumx += x[kk]; sumy += y[kk]; } sumx /= n_cov; sumy /= n_cov; for(kk = 0; kk<n_cov; kk++) { sum += (x[kk]-sumx)*(y[kk]-sumy); } sum /= (n_cov-1); return sum; }
5.求矩阵特征值和特征向量
这个短时间自己造轮子太麻烦了,,参考csdn上一篇博客:https://blog.csdn.net/zhouxuguang236/article/details/40212143 改了一下
/********参数表******* * @brief 求实对称矩阵的特征值及特征向量的雅克比法 * 利用雅格比(Jacobi)方法求实对称矩阵的全部特征值及特征向量 @Parameter pMatrix 长度为n*n的数组,存放实对称矩阵 @Parameter nDim 矩阵的阶数 @Parameter pdblVects 长度为n*n的数组,返回特征向量(按列存储) @Parameter dbEps 精度要求 @Parameter nJt 整型变量,控制最大迭代次数 @Parameter pdbEigenValues 特征值数组 ***********************/ void JacbiCor(double * pMatrix,int nDim, double *pdblVects, double *pdbEigenValues, double dbEps,int nJt) { int i,j; for(i = 0; i < nDim; i ++) { pdblVects[i*nDim+i] = 1.0f; for(int j = 0; j < nDim; j ++) { if(i != j) pdblVects[i*nDim+j]=0.0f; } } int nCount = 0; //迭代次数 while(1) { //在pMatrix的非对角线上找到最大元素 double dbMax = pMatrix[1]; int nRow = 0; int nCol = 1; for (i = 0; i < nDim; i ++) //行 { for (j = 0; j < nDim; j ++) //列 { double d = fabs(pMatrix[i*nDim+j]); if((i!=j) && (d> dbMax)) { dbMax = d; nRow = i; nCol = j; } } } if(dbMax < dbEps) //精度符合要求 break; if(nCount > nJt) //迭代次数超过限制 break; nCount++; double dbApp = pMatrix[nRow*nDim+nRow]; double dbApq = pMatrix[nRow*nDim+nCol]; double dbAqq = pMatrix[nCol*nDim+nCol]; //计算旋转角度 double dbAngle = 0.5*atan2(-2*dbApq,dbAqq-dbApp); double dbSinTheta = sin(dbAngle); double dbCosTheta = cos(dbAngle); double dbSin2Theta = sin(2*dbAngle); double dbCos2Theta = cos(2*dbAngle); pMatrix[nRow*nDim+nRow] = dbApp*dbCosTheta*dbCosTheta + dbAqq*dbSinTheta*dbSinTheta + 2*dbApq*dbCosTheta*dbSinTheta; pMatrix[nCol*nDim+nCol] = dbApp*dbSinTheta*dbSinTheta + dbAqq*dbCosTheta*dbCosTheta - 2*dbApq*dbCosTheta*dbSinTheta; pMatrix[nRow*nDim+nCol] = 0.5*(dbAqq-dbApp)*dbSin2Theta + dbApq*dbCos2Theta; pMatrix[nCol*nDim+nRow] = pMatrix[nRow*nDim+nCol]; for(i = 0; i < nDim; i ++) { if((i!=nCol) && (i!=nRow)) { int u = i*nDim + nRow; //p int w = i*nDim + nCol; //q dbMax = pMatrix[u]; pMatrix[u]= pMatrix[w]*dbSinTheta + dbMax*dbCosTheta; pMatrix[w]= pMatrix[w]*dbCosTheta - dbMax*dbSinTheta; } } for (j = 0; j < nDim; j ++) { if((j!=nCol) && (j!=nRow)) { int u = nRow*nDim + j; //p int w = nCol*nDim + j; //q dbMax = pMatrix[u]; pMatrix[u]= pMatrix[w]*dbSinTheta + dbMax*dbCosTheta; pMatrix[w]= pMatrix[w]*dbCosTheta - dbMax*dbSinTheta; } } //计算特征向量 for(i = 0; i < nDim; i ++) { int u = i*nDim + nRow; //p int w = i*nDim + nCol; //q dbMax = pdblVects[u]; pdblVects[u] = pdblVects[w]*dbSinTheta + dbMax*dbCosTheta; pdblVects[w] = pdblVects[w]*dbCosTheta - dbMax*dbSinTheta; } } for(i = 0; i < nDim; i ++) { pdbEigenValues[i] = pMatrix[i*nDim+i]; } //设定正负号 for(i = 0; i < nDim; i ++) { double dSumVec = 0; for(j = 0; j < nDim; j ++) dSumVec += pdblVects[j * nDim + i]; if(dSumVec<0) { for(j = 0;j < nDim; j ++) pdblVects[j * nDim + i] *= -1; } } }
二维数组转一维数组:
const short m_cov = 3; const short n_cov = 3; short X[m_cov][n_cov] = {0}; short *XFlat; /************X测试************/ X[0][0] = 7;X[0][1] = 1;X[0][2] = 8; X[1][0] = 4;X[1][1] = 5;X[1][2] = 8; X[2][0] = 10;X[2][1] = 4;X[2][2] = 2; /*****************************/ XFlat = (short *)X;