Sandeepin最近做的项目中需要在嵌入式芯片里跑一些算法,而这些单片机性能不上不下,它能跑些简单的程序,但又还没到上Linux系统的地步。所以只好用C语言写一些在高级语言里一个函数就解决的算法了,由于算法需要运用矩阵运算,自己就先用纯C语言写了个简单的矩阵运算库。

  代码只实现了矩阵最基本的运算,包括矩阵的加、减、乘、数乘、转置、行列式、逆矩阵、代数余子式、伴随矩阵等运算。此外增加了一些实用函数,如显示矩阵、从csv文件读取保存矩阵等函数。具体的例子在主函数中体现,其中还用自己这个矩阵运算库做了一个简单的应用,利用公式β=(X'X)^(-1)X'Y来进行多元线性回归系数计算,大家可以参考参考,欢迎批评。

  JfzMatLib.c文件代码:

#include "JfzMatLib.h"

int main(int argc, char** argv)
{
//矩阵的基本运算:加、减、乘、数乘、转置、行列式、逆矩阵、代数余子式、伴随矩阵
//初始实验矩阵
double A[] = { -3, 2, -5, -1, 0, -2, 3, -4, 1 };
double B[] = { 1, 4, 7, 3, 0, 5, -1, 9, 11 };
double C[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//计算结果矩阵
double *Add = (double*)malloc(sizeof(double) * 9);
double *Sub = (double*)malloc(sizeof(double) * 9);
double *Mul = (double*)malloc(sizeof(double) * 9);
double *kMat = (double*)malloc(sizeof(double) * 9);
double *CT = (double*)malloc(sizeof(double) * 9);
double *AInv = (double*)malloc(sizeof(double) * 9);
double *Adj = (double*)malloc(sizeof(double) * 9);
//显示矩阵A、B、C
printf("A:\n"); MatShow(A, 3, 3);
printf("B:\n"); MatShow(B, 3, 3);
printf("C:\n"); MatShow(C, 3, 3);
//矩阵相加
printf("A+B:\n");
Add = MatAdd(A, B, 3, 3); MatShow(Add, 3, 3);
//矩阵相减
printf("A-B:\n");
Sub = MatSub(A, B, 3, 3); MatShow(Sub, 3, 3);
//矩阵相乘
printf("A*B:\n");
Mul = MatMul(A, 3, 3, B, 3, 3); MatShow(Mul, 3, 3);
//矩阵数乘
printf("2*C:\n");
kMat = MatMulk(C, 3, 3, 2); MatShow(kMat, 3, 3);
//矩阵转置
printf("C的转置:\n");
CT = MatT(C, 3, 3); MatShow(CT, 3, 3);
//矩阵行列式值
printf("B的行列式值:\n");
printf("%16lf\n", MatDet(B, 3));
printf("C的行列式值:\n");
printf("%16lf\n", MatDet(C, 3));
//矩阵的逆
printf("A的逆:\n");
AInv = MatInv(A, 3, 3); MatShow(AInv, 3, 3);
printf("C的逆:\n");
MatInv(C, 3, 3);
//矩阵代数余子式
printf("C的(0,0)元素的代数余子式:\n");
printf("%16lf\n", MatACof(C, 3, 0, 0));
//矩阵伴随矩阵
printf("A的伴随矩阵:\n");
Adj = MatAdj(A, 3, 3); MatShow(Adj, 3, 3); //蒋方正矩阵库应用:多元线性回归
//多元线性回归公式:β=(X'X)^(-1)X'Y
double X[15][5] = {
1, 316, 1536, 874, 981,//第一列要补1
1, 385, 1771, 777, 1386,
1, 299, 1565, 678, 1672,
1, 326, 1970, 785, 1864,
1, 441, 1890, 785, 2143,
1, 460, 2050, 709, 2176,
1, 470, 1873, 673, 1769,
1, 504, 1955, 793, 2207,
1, 348, 2016, 968, 2251,
1, 400, 2199, 944, 2390,
1, 496, 1328, 749, 2287,
1, 497, 1920, 952, 2388,
1, 533, 1400, 1452, 2093,
1, 506, 1612, 1587, 2083,
1, 458, 1613, 1485, 2390
};
double Y[15][1] = {
3894,
4628,
4569,
5340,
5449,
5599,
5010,
5694,
5792,
6126,
5025,
5924,
5657,
6019,
6141
};
//多元线性回归公式:β=(X'X)^(-1)X'Y
double *XT = (double*)malloc(sizeof(double) * 5 * 15);
double *XTX = (double*)malloc(sizeof(double) * 5 * 5);
double *InvXTX = (double*)malloc(sizeof(double) * 5 * 5);
double *InvXTXXT = (double*)malloc(sizeof(double) * 5 * 15);
double *InvXTXXTY = (double*)malloc(sizeof(double) * 5 * 1);
XT = MatT((double*)X, 15, 5);
XTX = MatMul(XT, 5, 15, (double*)X, 15, 5);
InvXTX = MatInv(XTX, 5, 5);
InvXTXXT = MatMul(InvXTX, 5, 5, XT, 5, 15);
InvXTXXTY = MatMul(InvXTXXT, 5, 15, (double*)Y, 15, 1);
printf("多元线性回归β系数:\n");
MatShow(InvXTXXTY, 5, 1); //保存矩阵到csv
MatWrite("XTX.csv", XTX, 5, 5);
MatWrite("InvXTXXTY.csv", InvXTXXTY, 5, 1);
MatWrite("Fuck.csv", A, 3, 3);
MatWrite("Fuck2.csv", A, 9, 1); //从csv读取矩阵
double *Fuck = (double*)malloc(sizeof(double) * 3 * 3);
Fuck = MatRead("Fuck.csv");
MatShow(Fuck, 3, 3); double *Fuck2 = (double*)malloc(sizeof(double) * 9 * 1);
Fuck2 = MatRead("Fuck2.csv");
MatShow(Fuck2, 9, 1); double *InvXTXXTYread = (double*)malloc(sizeof(double) * 5 * 1);
InvXTXXTYread = MatRead("InvXTXXTY.csv");
MatShow(InvXTXXTYread, 5, 1); double *XTXread = (double*)malloc(sizeof(double) * 5 * 5);
XTXread = MatRead("XTX.csv");
MatShow(XTXread, 5, 5);
system("pause");
}

  JfzMatLib.h头文件代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> void MatShow(double* Mat, int row, int col);
double* MatAdd(double* A, double* B, int row, int col);
double* MatSub(double* A, double* B, int row, int col);
double* MatMul(double* A, int Arow, int Acol, double* B, int Brow, int Bcol);
double* MatMulk(double *A, int row, int col, double k);
double* MatT(double* A, int row, int col);
double MatDet(double *A, int row);
double* MatInv(double *A, int row, int col);
double MatACof(double *A, int row, int m, int n);
double* MatAdj(double *A, int row, int col);
double *MatRead(char *csvFileName, int row, int col);
void MatWrite(char *A, int row, int col); // (det用)功能:求逆序对的个数
int inver_order(int list[], int n)
{
int ret = 0;
for (int i = 1; i < n; i++)
for (int j = 0; j < i; j++)
if (list[j] > list[i])
ret++;
return ret;
} // (det用)功能:符号函数,正数返回1,负数返回-1
int sgn(int order)
{
return order % 2 ? -1 : 1;
} // (det用)功能:交换两整数a、b的值
void swap(int *a, int *b)
{
int m;
m = *a;
*a = *b;
*b = m;
} // 功能:求矩阵行列式的核心函数
double det(double *p, int n, int k, int list[], double sum)
{
if (k >= n)
{
int order = inver_order(list, n);
double item = (double)sgn(order);
for (int i = 0; i < n; i++)
{
//item *= p[i][list[i]];
item *= *(p + i * n + list[i]);
}
return sum + item;
}
else
{
for (int i = k; i < n; i++)
{
swap(&list[k], &list[i]);
sum = det(p, n, k + 1, list, sum);
swap(&list[k], &list[i]);
}
}
return sum;
} // 功能:矩阵显示
// 形参:(输入)矩阵首地址指针Mat,矩阵行数row和列数col。
// 返回:无
void MatShow(double* Mat, int row, int col)
{
for (int i = 0; i < row*col; i++)
{
printf("%16lf ", Mat[i]);
if (0 == (i + 1) % col) printf("\n");
}
} // 功能:矩阵相加
// 形参:(输入)矩阵A首地址指针A,矩阵B首地址指针B,矩阵A(也是矩阵B)行数row和列数col
// 返回:A+B
double* MatAdd(double* A, double* B, int row, int col)
{
double *Out = (double*)malloc(sizeof(double) * row * col);
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
Out[col*i + j] = A[col*i + j] + B[col*i + j];
return Out;
} // 功能:矩阵相减
// 形参:(输入)矩阵A,矩阵B,矩阵A(也是矩阵B)行数row和列数col
// 返回:A-B
double* MatSub(double* A, double* B, int row, int col)
{
double *Out = (double*)malloc(sizeof(double) * row * col);
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
Out[col*i + j] = A[col*i + j] - B[col*i + j];
return Out;
} // 功能:矩阵相乘
// 形参:(输入)矩阵A,矩阵A行数row和列数col,矩阵B,矩阵B行数row和列数col
// 返回:A*B
double* MatMul(double* A, int Arow, int Acol, double* B, int Brow, int Bcol)
{
double *Out = (double*)malloc(sizeof(double) * Arow * Bcol);
if (Acol != Brow)
{
printf(" Shit!矩阵不可乘!\n");
return NULL;
}
if (Acol == Brow)
{
int i, j, k;
for (i = 0; i < Arow; i++)
for (j = 0; j < Bcol; j++)
{
Out[Bcol*i + j] = 0;
for (k = 0; k < Acol; k++)
Out[Bcol*i + j] = Out[Bcol*i + j] + A[Acol*i + k] * B[Bcol*k + j];
}
return Out;
}
} // 功能:矩阵数乘(实数k乘以矩阵A)
// 形参:(输入)矩阵A首地址指针,矩阵行数row和列数col,实数k
// 返回:kA
double* MatMulk(double *A, int row, int col, double k)
{
double *Out = (double*)malloc(sizeof(double) * row * col);
for (int i = 0; i < row * col; i++)
{
*Out = *A * k;
Out++;
A++;
}
Out = Out - row * col;
return Out;
} // 功能:矩阵转置
// 形参:(输入)矩阵A首地址指针A,行数row和列数col
// 返回:A的转置
double* MatT(double* A, int row, int col)
{
double *Out = (double*)malloc(sizeof(double) * row * col);
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
Out[row*j + i] = A[col*i + j];
return Out;
} // 功能:求行列式值
// 形参:(输入)矩阵A首地址指针A,行数row
// 返回:A的行列式值
double MatDet(double *A, int row)
{
int *list = (int*)malloc(sizeof(int) * row);
for (int i = 0; i < row; i++)
list[i] = i;
double Out = det(A, row, 0, list, 0.0);
free(list);
return Out;
} // 功能:矩阵的逆
// 形参:(输入)矩阵A首地址指针A,行数row和列数col
// 返回:A的逆
double *MatInv(double *A, int row, int col)
{
double *Out = (double*)malloc(sizeof(double) * row * col);
double det = MatDet(A, row); //求行列式
if (det == 0)
{
printf(" Fuck!矩阵不可逆!\n");
return NULL;
}
if (det != 0)
{
Out = MatAdj(A, row, col); //求伴随矩阵
int len = row * row;
for (int i = 0; i < len; i++)
*(Out + i) /= det;
return Out;
}
} // 功能:求代数余子式
// 形参:(输入)矩阵A首地址指针A,矩阵行数row, 元素a的下标m,n(从0开始),
// 返回:NxN 矩阵中元素A(mn)的代数余子式
double MatACof(double *A, int row, int m, int n)
{
int len = (row - 1) * (row - 1);
double *cofactor = (double*)malloc(sizeof(double) * len); int count = 0;
int raw_len = row * row;
for (int i = 0; i < raw_len; i++)
if (i / row != m && i % row != n)
*(cofactor + count++) = *(A + i);
double ret = MatDet(cofactor, row - 1);
if ((m + n) % 2)
ret = -ret;
free(cofactor);
return ret;
} // 功能:求伴随矩阵
// 形参:(输入)矩阵A首地址指针A,行数row和列数col
// 返回:A的伴随矩阵
double *MatAdj(double *A, int row, int col)
{
double *Out = (double*)malloc(sizeof(double) * row * col);
int len = row * row;
int count = 0;
for (int i = 0; i < len; i++)
{
*(Out + count++) = MatACof(A, row, i % row, i / row);
}
return Out;
} // 读取文件行数
int FileReadRow(const char *filename)
{
FILE *f = fopen(filename, "r");
int i = 0;
char str[4096];
while (NULL != fgets(str, 4096, f))
++i;
printf("数组行数:%d\n", i);
return i;
} // 读取文件每行数据数(逗号数+1)
int FileReadCol(const char *filename)
{
FILE *f = fopen(filename, "r");
int i = 0;
char str[4096];
fgets(str, 4096, f);
for (int j = 0; j < strlen(str); j++)
{
if (',' == str[j]) i++;
}
i++;// 数据数=逗号数+1
printf("数组列数:%d\n", i);
return i;
} // 逗号间隔数据提取
void GetCommaData(char str_In[4096], double double_Out[1024])
{
int str_In_len = strlen(str_In);
//printf("str_In_len:%d\n", str_In_len);
char str_Data_temp[128];
int j = 0;
int double_Out_num = 0;
for (int i = 0; i < str_In_len; i++)
{
//不是逗号,则是数据,存入临时数组中
if (',' != str_In[i]) str_Data_temp[j++] = str_In[i];
//是逗号或\n(最后一个数据),则数据转换为double,保存到输出数组
if (',' == str_In[i] || '\n' == str_In[i]) { str_Data_temp[j] = '\0'; j = 0; /*printf("str_Data_temp:%s\n", str_Data_temp); */double_Out[double_Out_num++] = atof(str_Data_temp); memset(str_Data_temp, 0, sizeof(str_Data_temp)); }
}
} // 功能:从csv文件读矩阵,保存到指针中
// 形参:(输入)csv文件名,预计行数row和列数col
// 返回:矩阵指针A
double *MatRead(char *csvFileName)
{
int row = FileReadRow(csvFileName);
int col = FileReadCol(csvFileName);
double *Out = (double*)malloc(sizeof(double) * row * col);
FILE *f = fopen(csvFileName, "r");
char buffer[4096];
while (fgets(buffer, sizeof(buffer), f))
{
//printf("buffer[%s]\n",buffer);
double double_Out[128] = { 0 };
GetCommaData(buffer, double_Out);
for (int i = 0; i < col; i++)
{
//printf("double_Out:%lf\n", double_Out[i]);
*Out = double_Out[i];
Out++;
} }
Out = Out - row * col;//指针移回数据开头
fclose(f);
return Out;
} // 功能:将矩阵A存入csv文件中
// 形参:(输入)保存的csv文件名,矩阵A首地址指针A,行数row和列数col
// 返回:无
void MatWrite(const char *csvFileName, double *A, int row, int col)
{
FILE *DateFile;
double *Ap = A;
DateFile = fopen(csvFileName, "w");//追加的方式保存生成的时间戳
for (int i = 0; i < row*col; i++)
{
if ((i+1) % col == 0) fprintf(DateFile, "%lf\n", *Ap);//保存到文件,到列数换行
else fprintf(DateFile, "%lf,", *Ap);//加逗号
Ap++;
}
fclose(DateFile);
}

  运行结果如图:

异想家纯C语言矩阵运算库的更多相关文章

  1. 异想家Golang学习笔记

    1. 简介 官网:https://golang.google.cn/ 2. 编译器.工具链 编译 go build .\demo.go 编译和执行指令合二为一 go run demo.go 3. 注释 ...

  2. 异想家Win10常用的软件推荐

    本文总结一下自己日常使用Win10中涉及到的好用小软件,那些装机必备的软件在这里就不一一列出了.我重点想推荐一些自己觉得好用,符合自己偏好,但又不是每个人都知道的小工具: Rolan:一款类似于Win ...

  3. 异想家Ubuntu安装的软件

    [替换国内源] https://developer.aliyun.com/mirror/ubuntu 我提供一个下载,方便第一次安装懒得敲命令: https://jfz.me/16.04/source ...

  4. 异想家Win10系统安装的软件与配置

    1.C盘推荐一个硬盘,256G,安装好驱动,显卡配置好高性能,激活Win10,屏蔽WIn10驱动更新(Show or hide updates.diagcab),改电脑名称为Sandeepin-PC. ...

  5. 异想家Win7系统安装的软件与配置

    C盘推荐一个硬盘,256G以上,安装好驱动,激活Win7,备份一次系统(纯净)! 1.Mac.Linux时间同步(双系统时配置): 开始->运行->CMD,打开命令行程序(以管理员方式打开 ...

  6. 异想家IDEA的偏好配置

    最好将配置文件位置改为软件安装目录下,因为只有自己用,易于便携. 修改bin目录下的idea.properties,注释#去掉修改idea.config.path.idea.system.path配置 ...

  7. 异想家Eclipse的偏好配置

    1.汉化 http://www.eclipse.org/babel/downloads.php 找到Babel Language Pack Zips,下面选自己版本点进去,找到如下类似的中文包: Ba ...

  8. 不好意思啊,我上周到今天不到10天时间,用纯C语言写了一个小站!想拍砖的就赶紧拿出来拍啊

    花10天时间用C语言做了个小站 http://tieba.yunxunmi.com/index.html 简称: 云贴吧 不好意思啊,我上周到今天不到10天时间,用纯C语言写了一个小站!想拍砖的就赶紧 ...

  9. 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

    Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解   多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...

随机推荐

  1. python内置模块(python标准库)

    1.time模块 掌握下面三种方式的转换 文件名不能跟系统内置模块重名!   #三种方式的转化关系 #时间戳(timestamp): 为了计时 为了减法计算   import time print(t ...

  2. MySQL的读写分离与主从同步数据一致性

    有没有做MySQL读写分离?如何实现mysql的读写分离?MySQL主从复制原理的是啥?如何解决mysql主从同步的延时问题? 高并发这个阶段,那肯定是需要做读写分离的,啥意思?因为实际上大部分的互联 ...

  3. 分布式全局唯一ID生成策略

    为什么分布式系统需要用到ID生成系统 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在美团点评的金融.支付.餐饮.酒店.猫眼电影等产品的系统中,数据日渐增长,对数据库的分库分表后需要有 ...

  4. shell脚本配置maven

    #!/bin/bash # maven install mvnpath=/usr/local/maven # 不存在 if [ ! -d "$mvnpath" ]; then ec ...

  5. Hadoop中的Partitioner浅析

    转自:http://blog.csdn.net/b1198103958/article/details/47169105 Hadoop里面的MapReduce编程模型,非常灵活,大部分环节我们都可以重 ...

  6. [Windows10]记一次修复注册表相关血案:该文件没有与之关联的应用来执行该操作。请安装应用,若已经安装应用,请在“默认应用设置”页面中创建关联。

    今天闲得蛋疼清理了一下右键菜单,于是在之后某时刻使用Everything的“双击路径列打开目录”功能时发现异常: [Window Title] Everything.exe [Content] 该文件 ...

  7. SqlBulkCopy批量插入和索引的关系

    .net中批量插入基本都用SqlBulkCopy,速度很快,但是这几天发现个问题,2000数据居然15s,百思不得其解.经过大量测试,发现过多的索引和索引碎片会严重影响插入速度,表的数据量大小反而不会 ...

  8. 一个简单的spring boot程序

    搭建一个spring boot项目十分的方便,网上也有许多,可以参考 https://www.cnblogs.com/ityouknow/p/5662753.html 进行项目的搭建.在此我就不详细介 ...

  9. Map and HashMap

    1.1.1. Map 接口 java提供了一组可以以键值对(key-value)的形式存储数据的数据结构,这种数据结构称为Map.我们可以把Map看成一个多行两列的表格,其中第一列存放key,第二列存 ...

  10. Go 每日一库之 go-flags

    简介 在上一篇文章中,我们介绍了flag库.flag库是用于解析命令行选项的.但是flag有几个缺点: 不显示支持短选项.当然上一篇文章中也提到过可以通过将两个选项共享同一个变量迂回实现,但写起来比较 ...