(C++)n阶方阵求逆

文章目录

  • 一、实验目的、内容
  • 二、实验程序设计及结构
    • 1.需求分析
      • 变量
      • 函数
    • 2.设计结构或流程图
  • 三、设计过程
  • 四、测试分析
    • 第一组
    • 第二组
    • 实验中出现的bug及解决方案
  • 五、设计的特点和结果

一、实验目的、内容

输入是一个 n n n n < 256 n<256 n<256)阶方阵 A A A,输出是它的逆矩阵,再将得到的逆矩阵与原来的矩阵相乘,验证其结果是单位矩阵。

二、实验程序设计及结构

1.需求分析

变量

二级指针a(double**)存储原矩阵的首地址,b(double**)存储逆矩阵的首地址,c(double**)存储乘积的首地址;数n(unsigned char)存储阶数;循环变量i(unsigned char),j(unsigned char)。

函数

求逆函数double** inv(const double** a, const unsigned char n),求积函数double** pro(const double** a, const double** b, const unsigned char n),主函数int main()

2.设计结构或流程图

  1. 输入原矩阵及矩阵的阶数。
  2. 求逆矩阵并输出。(调用求逆函数)
    1. 在堆区开辟两个二维数组,其中一个初始化为原矩阵,另一个初始化为单位矩阵。
    2. 从首行开始逐行进行初等行变换,将原矩阵化为阶梯型,对单位矩阵进行同等操作。
    3. 从最后一行开始逐行消元素,直到将原矩阵化为单位矩阵为止。
  3. 分别对原矩阵和逆矩阵左乘和右乘进行验证并输出。(调用求积函数)
  4. 释放堆区数据并退出。

三、设计过程

#include <iostream>
#define abs(a) (a > 0 ? a : -a)
using namespace std;
// 求逆函数
double **inv(double **a, unsigned char n)
{unsigned char i, j, k = -1;double **t = new double *[n], **b = new double *[n]; // t作为逆矩阵,b作为原矩阵的副本// 拷贝a并把t初始化为单位矩阵for (i = 0; i < n; ++i){t[i] = new double[n];b[i] = new double[n];for (j = 0; j < n; ++j){b[i][j] = a[i][j];if (i == j)t[i][j] = 1.;elset[i][j] = 0.;}}double x;double *w;while (++k < n) // 化原矩阵为阶梯型{// 第k行第k列为零,在第k列中寻找不为零的元素if (abs(b[k][k]) < 1e-5){i = k;// 由于浮点数为二进制指数表达,在计算过程中可能出现偏差// 所以将1e-5到-1e-5之间的数据近似地视为0doif (++i == n)return nullptr;while (abs(b[i][k]) < 1e-5); // 如果遍历完了整行,证明行列式为0,逆矩阵不存在w = b[i];b[i] = b[k];b[k] = w; // 交换找到的行w = t[i];t[i] = t[k];t[k] = w; // 对逆矩阵做同样的初等行变换}for (i = k + 1; i < n; ++i){x = b[i][k] / b[k][k]; // 记录比例系数for (j = k + 1; j < n; ++j)b[i][j] -= x * b[k][j]; // 对原矩阵做初等行变换for (j = 0; j <= k; ++j)t[i][j] -= x * t[k][j]; // 对逆矩阵做同样的初等行变换}x = b[k][k];// 将b[k][k]变为1,由于b[k][k]在接下来的程序里无用,故i从k+1开始for (i = k + 1; i < n; ++i)b[k][i] /= x;for (i = 0; i <= k; ++i)t[k][i] /= x; // 对逆矩阵做同样的初等行变换}do // 化为单位矩阵{i = --k;do{x = b[--i][k];for (j = 0; j < n; ++j)t[i][j] -= x * t[k][j];} while (i > 0);delete[] b[k]; // 防止内存泄漏} while (k > 1);delete[] *b;delete[] b;return t;
}
double **pro(double **a, double **b, unsigned char n) // 方阵乘法
{double **p = new double *[n], *q;for (unsigned char i = 0; i < n; ++i){q = p[i] = new double[n];for (unsigned char j = 0; j < n; ++j){*q = *a[i] * b[0][j];for (unsigned char k = 1; k < n; ++k)*q += a[i][k] * b[k][j];++q;}}return p;
}
int main()
{unsigned short n; // 为了输入方便,故采用unsigned shortcout << "请输入方阵的阶数:\n";cin >> n;cout << "请输入方阵:\n";double **a = new double *[n];// 由于a是指针类型而非数组类型,故不能用范围for循环for (unsigned char i = 0; i < n; ++i){a[i] = new double[n];for (unsigned char j = 0; j < n; ++j)cin >> a[i][j];}double **b = inv(a, n);if (!b){cout << "逆矩阵不存在!\n";system("pause");return 0;}cout << "逆矩阵为:\n";for (unsigned char i = 0; i < n; ++i){for (unsigned char j = 0; j < n; ++j)cout << b[i][j] << '\t';cout << endl;}cout << "原矩阵右乘逆矩阵为:\n";double **c = pro(a, b, n);for (unsigned char i = 0; i < n; ++i){for (unsigned char j = 0; j < n; ++j)cout << c[i][j] << '\t';delete[] c[i]; // 防止内存泄漏cout << endl;}delete[] c;cout << "原矩阵左乘逆矩阵为:\n";c = pro(b, a, n);for (unsigned char i = 0; i < n; ++i){for (unsigned char j = 0; j < n; ++j)cout << c[i][j] << '\t';delete[] c[i]; // 防止内存泄漏delete[] a[i];delete[] b[i];cout << endl;}delete[] c;delete[] a;delete[] b;system("pause");return 0;
}

四、测试分析

第一组

第二组

实验中出现的bug及解决方案

bug解决方案
未考虑行列式为0的情况返回空指针
由于浮点数计算的不精确,容易出现大数-1e-51e-5之间的数据近似视为0

五、设计的特点和结果

采用初等变换法求逆矩阵,较伴随矩阵法较复杂,但避免了递归,效率更高。

结果:求得逆矩阵。但由于浮点数运算的偏差,容易出现极小数,往后可以通过编写一个有理数类加以解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/422310.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins 还可以支持钉钉消息通知?一个插件带你搞定!

Jenkins 作为最流行的开源持续集成平台&#xff0c;其强大的拓展功能一直备受测试人员及开发人员的青睐。大家都知道我们可以在 Jenkins 中安装 Email 插件支持构建之后通过邮件将结果及时通知到相关人员。 但其实 Jenkins 还可以支持钉钉消息通知&#xff0c;其主要通过 Ding…

【C++】入门(一)

前言&#xff1a; 本篇博客将带大家认识C&#xff0c;熟悉基本语法 文章目录 认识CC的诞生与发展C 在行业中的运用 一、命名空间1.1 命名空间的定义1.2 命名空间的使用1.3 命名空间的访问 二、C输入&输出输出操作符 <<输入操作符 >>换行符和刷新输出缓冲区关键…

论文阅读:Vary论文阅读笔记

目录 引言整体结构图数据集构造Vary-tiny部分Document Data数据构造Chart Data构造Negative natural image选取 Vary-base部分 引言 论文&#xff1a;Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models Paper | Github | Demo 许久不精读论文了&#x…

如何查看Linux CPU占有率

目录 1、top 2、htop 3、vmstat 4、mpstat 5、iostat 查看嵌入式设备CPU占有率是评估系统资源使用情况的重要方式。 在Linux系统中&#xff0c;有多种方法可以查看CPU占有率&#xff0c;这里介绍几种常用的命令行工具。 1、top 这是最常用的命令之一&#xff0c;它提供了…

Unity 编辑器篇|(十三)自定义属性绘制器(PropertyDrawer ,PropertyAttribute) (全面总结 | 建议收藏)

目录 1. 前言2. PropertyDrawer2.1 参数总览2.2 两种用途2.3 注意事项2.4 代码样例 3. PropertyDrawer与PropertyAttribute结合使用 1. 前言 在Unity中&#xff0c;PropertyDrawer和PropertyAttribute是两个重要的工具&#xff0c;它们主要用于自定义属性的显示和行为。Proper…

U-Boot 命令解析(一)

U-Boot 命令解析&#xff08;一&#xff09; 查询命令环境变量操作命令修改环境变量新建环境变量删除环境变量&#xff0c; 内存操作命令内存查看命令 md内存修改命令 nm内存修改命令 mm内存填充命令 mw内存拷贝命令 cp内存对比命令 cmp 更多内容 一般情况下&#xff0c;U-Boot…

亚马逊KYC审核的重要性,所需提交的文件有哪些?—站斧浏览器

亚马逊KYC审核的重要性有哪些&#xff1f; KYC审核是亚马逊对卖家身份的一种验证&#xff0c;确保卖家遵守相关法规。只有通过审核的卖家才能在欧洲平台进行销售。因此&#xff0c;正确理解和应对KYC审核对于卖家来说至关重要。 注册完成后立即触发&#xff1a;新注册的卖家可…

const关键字

修饰常量 const int a 10; int const a 10; 常量指针 以下两种方式等价 const int *a; int const *a; 常量指针说的是不可以通过指针改变指向内容的值&#xff0c;但是可以重新指向新的地址, 因此一般用作函数参数&#xff0c;防止内部通过指针地址中保存的值void test(…

Netty篇章(1)—— 核心原理介绍

终于进入到Netty框架的环节了&#xff0c;前面介绍了大量的Java-NIO的内容&#xff0c;核心的内容Selector、Channel、Buffer、Reactor掌握了&#xff0c;那么学起来Netty也是水到渠成的事情。如果没有掌握前面的内容那么学Netty会非常吃力&#xff0c;下面讲解Netty核心原理与…

机械设计-哈工大课程学习-螺旋传动

二、摩擦类型 1、静态摩擦&#xff1a;这是身体静止时所经历的摩擦。换句话说&#xff0c;就是身体有运动倾向时的摩擦力。 2、动态摩擦&#xff1a;这是身体在运动时所经历的摩擦。也称为动摩擦。动摩擦有以下两种类型&#xff1a; ①滑动摩擦&#xff1a;一个物体在另一个…

【深蓝学院】移动机器人运动规划--第2章 基于搜索的路径规划--笔记

0. Outline 1. Graph Search Basis Configuration Space等概念 机器人配置: 指机器人位置和所有点的表示。 DOF: 指用于表示机器人配置所需的最小的实数坐标的数量n。 C-space: 包含机器人n维所有配置的空间。 在C-space中机器人的pose是一个点。 机器人在C-space中被表示为一…

stm32中的SPI

SPI的简介 文章目录 SPI的简介物理层协议层基本通讯过程起始和终止信号数据有效性CPOL/CPHA及通讯模式 STM3的SPI特性及架构通讯引脚时钟控制逻辑数据控制逻辑整体控制逻辑通讯过程 代码配置实现结构体的定义SPI时钟信号的定义SPI端口定义SPI命令 flash驱动代码初始化代码(配置…