C/C++描述 - 矩阵乘积的计算

news2024/11/20 23:30:14

矩阵运算是现代科学及工程计算的基石之一,而矩阵乘法则是其中最常见一种运算。对于二维矩阵A、B,如果A的列数等于B的行数,则矩阵A、B可乘,其结果矩阵C的行数等于A的行数,列数等于B的列数。

本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

形式化表达为:
在这里插入图片描述
其中,cij表示结果矩阵中第i行第j列的元素,其计算公式为:
在这里插入图片描述
下述示例中,一个3行2列的矩阵乘以一个2行3列的矩阵,其结果矩阵为3行3列。
在这里插入图片描述
对于结果矩阵的第i行第j列的元素,其值正好等于A阵的第i行和B阵的第j列的元素两两相乘,再求和。本例中,结果矩阵第2行第3列的元素值为49,它通过下列计算而得:
4×4+3×11=49

请读者注意,上述表述中我们依从数学课本的习惯,行列从1开始计数。后续示例代码则按照程序设计的规则从0开始计数。

下述代码中的multiMatrix()函数实现了不同行列数的二维矩阵的通用乘法。

//Project - MulMatrix
#include <iostream>
#include <iomanip>  //引入格式操作算子(manipulator),详见2.3节扩展阅读

bool multiMatrix(const int a[], int aRow, int aCol,
                 const int b[], int bRow, int bCol,
                 int c[], int cRow, int cCol){
    if ((aCol!=bRow) || (aRow!=cRow) || (bCol!=cCol)
        || (aRow<=0) || (bRow<=0) || (bCol<=0))
        return false;

    for (int i=0;i<cRow;i++)
        for (int j=0;j<cCol;j++){
            c[i*cCol+j] = 0;
            for (int k=0;k<aCol;k++)
                c[i*cCol+j] += a[i*aCol+k] * b[k*bCol+j];
        }
    return  true;
}

int main(){
    using namespace std;
    int a[] = { 5,7,4,3,6,1 };
    int b[] = { -3,2,4,4,1,11 };
    int c[9];
    if (!multiMatrix(a,3,2,b,2,3,c,3,3)){
        cout << "Illegal parameters for matrix multiply.";
        return 0;
    }

    for (int i=0;i<3;i++){
        for (int j=0;j<3;j++)
            cout << setw(5) << c[i*3+j]; //set(w)设置输出宽度为5个字符
        cout << "\n";
    }
    return 0;
}

上述代码的执行结果为:

 13   17   97
  0   11   49
-14   13   35

依本章稍早的讨论,当程序根据下标去访问二维数组的特定元素时,依赖于每行的元素个数,即列数来计算单个元素的存储位置。对于multiMatrix()函数,如果我们以二维数组的形式设计形参的话,就只能将其声明为下述形式:

bool multiMatrix(const int a[][2], int aRow,       //二维数组作为参数
                 const int b[][3], int bRow, 
                 int c[][3], int cRow);

该函数声明包含6个形参,其中a、b两个二维数组所代表的矩阵相乘的结果矩阵存储在二维数组c当中,aRow、bRow、cRow分别代表了三个矩阵的行数,矩阵的列数已包含在形参a、b、c的定义中。 请读者注意,上述声明中二维数组的行数被省略,这是允许的,因为程序依赖于列数来计算单个元素的存储位置,但不依赖于行数。

显然,这种以二维数组来表示矩阵的方式使得multiMatrix()函数不够通用,其只能计算特定维度的矩阵的乘积。为了确保multiMatrix()函数的通用性,我们将二维数组“扁平化”,降维成一维数组。当我们在函数中按行号i和列号j访问矩阵的特定元素时,总是通过计算求得其在对应的一维数组中的下标来进行访问。

不失一般性,对于二维数组C2,如果将其降维存储为一维数组C1,则有:
在这里插入图片描述
🚩第5行:形参一维数组a代表被乘矩阵A,在程序中,其为一维数组,但读者需要将其理解为aRow行aCol列的二维数组。在函数执行过程中,矩阵A预期不应被修改,故a的元素类型设定为const int。请读者注意,const int a[]表示a为一个一维数组,其元素类型为const int,其元素个数不确定。当程序第26行的函数调用发生时,实参a向形参a的传递并非传递整个数组,实际被传递的是数组名,即数组首元素的地址。在函数内对形参数组a的访问,即是对第23行的实参数组a的访问。

🚩第6行:形参一维数组b代表乘数矩阵B,其含义同形参a。

🚩第7行:形参一维数组c代表结果矩阵C,其行数为cRow,列数为cCol。请读者注意,确保c数组有恰当的存储空间以容纳结果矩阵,是外部程序而不是本函数的职责。

🚩第8 ~ 10行:对参数的合法性进行检查,包括行列数是否大于0,A的列数是否等于B的行数,A的行数是否等于C的行数等。如不合法,返回false。

🚩第12 ~ 17行:按照计算公式逐一计算结果矩阵C中每一个元素cij 的值。第12 ~ 13行是一个双重循环,其内层循环即j循环的循环体用于计算cij 的值。第14行首先将cij 置0,第15 ~ 16行则依公式将矩阵A的第i行与矩阵B的第j列两两相乘,并累加至cij 。请读者留意第14 ~ 17行中一维数组a、b、c的下标,其是按“ 行号x列数+列号”的形式计算而得的,代表了元素在“假想的”的二维数组中的对应位置。

🚩第23行:3行2列矩阵A的扁平化一维数组。逻辑上,矩阵A的值如下:
在这里插入图片描述
🚩第24行:2行3列矩阵B的扁平化一维数组。

🚩第25行:3行3列的结果矩阵C的扁平化一维数组,其包含9个元素。

🚩第26 ~ 29行:调用multiMatrix()函数计算矩阵A乘以矩阵B的积。如果计算失败,打印错误信息并返回。

🚩第31 ~ 35行:将结果矩阵打印出来。其中,setw(5)格式操作算子(manipulator)指定了整数输出的宽度为5个字符。第34行代码在每行数据输出完毕后添加一个换行符。同样地,第33行的下标[i*3+j]对应“假想”的二维数组下标[i][j],在该“假想”的二维数组中,列数为3。

关于格式操作算子及通过cout进行复杂格式的输出,请参见2.3节扩展阅读部分。

扩展阅读📕
矩阵乘法的计算复杂性
在上述示例中,结果矩阵包括m行n列共mn个元素,对于每个结果元素的计算,需要执行一个q轮的循环。因此,整个计算过程中第16行代码需要执行mnq次。在代码的第16行中,包括至少4次乘法,4次加法运算,如果我们将这些运算用“1”次来代替,则最终的估计值比实际值至少小8倍,但不会超过常数倍。如此简化之后,我们称一次矩阵乘法需要执行mnq次“基本运算”。进一步地,矩阵的行数列数之比不会超过常数倍,故我们用参数n来表征矩阵的行/列数,称一次矩阵乘法需要执行n3次“基本运算”。如此简化之后,估计值与实际值之比也不会超过常数倍。在《算法分析》这样的课程中,我们称矩阵乘法的计算复杂性为θ(n3) 。请读者注意,这里所谓的常数,是指任意小于无穷大的确定值。之所以在计算复杂性估计的过程中可以忽略常数倍的差异,理由之一是常数倍的计算量差异可以通过提高计算机速度等途径来弥补。

为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

简洁的C及C++
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造
Python编程基础及应用
由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造

如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

Python编程基础及应用

Python编程基础及应用实验教程
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS || ENVI:如何将彩色影像拆分为R、G、B以及H、S、I(B/V)影像?

目录 01 加载RGB影像数据 02 分别将三个波段进行保存 03 将RGB三色图像转化为HSI(HSB或者叫HSV)图像 04 转换的HSI图像拆分成H、S、I三个影像 首先&#xff0c;需要明确&#xff0c;手机拍摄的影像即是Red、Green、Blue三波段影像&#xff1b; 另外&#xff0c;由于方法十分…

视觉合集3

这次的合集是找到了几个论文... 一起来说下 Fast Charging of Energy-dense Lithium-ion Batteries Real-time Short Video Recommendation on Mobile Devices Semantic interpretation for convolutional neural networks: What makes a cat a cat? Prompt-to-Prompt Ima…

【论文阅读】Pre-training Methods in Information Retrieval

文章目录前言Abs1.Intro2.Background2.1.A Hierarchical View of IR2.1.1.The Core Problem View of IR2.1.2.The Framework View of IR2.1.3.The System View of IR2.2.A Brief Overview of PTMs in IR前言 因为文章篇幅较长&#xff0c;因此还在持续阅读中原文&#xff08;F…

科研初体验之Linux服务器的入门使用,关于分配了Linux账号之后怎么用,以及怎么利用Linux服务器来跑我们的python代码

前情提要 如果有人看了我之前发的乱七八糟的博客的话&#xff0c;应该就能了解到&#xff0c;我之前是计算机专业大三的学生&#xff0c;好不容易get到了保研的名额&#xff0c;前段时间就一直在操练LeetCode&#xff0c;到处报夏令营啊&#xff0c;预推免什么的&#xff0c;最…

应该了解的网络知识

今天上午10&#xff1a;00参加了一个新华三杯&#xff0c;是关于计算机网络的&#xff0c;100道题&#xff0c;发现没有一道是自己会的&#xff0c;好歹也是学过一学期的计算机网络&#xff0c;到头来发现啥也不会&#xff0c;然后现在就又去复习一下网络。 OSI七层模型 *应用层…

VUE | “面包屑”的原理

最近我在写一个“项目”&#xff1f;遇到了以前没有接触到的一个知识点——“面包屑”。 写下来&#xff0c;我所理解的思路&#xff0c;一是为了看能不能帮助到大家&#xff0c;二是自己肯定不是已经完全理解、印在脑子里了&#xff0c;所以方便自己随时复习~ 我们先来看一下…

自动化测试项目学习笔记(五):Pytest结合allure生成测试报告以及重构项目

相关文章 [ >.<] 自动化测试项目学习笔记(一)&#xff1a;unittest简单运行&#xff08;初始化&#xff0c;清除&#xff0c;设置测试行为&#xff09;[ >.<] 自动化测试项目学习笔记(二)&#xff1a;学习各种setup、tearDown、断言方法[ >.<] 自动化测试项…

启发式算法之蚁群算法

&#x1f63b;今天我们来学习启发式算法中的蚁群算法&#xff0c;据说&#xff0c;蚁群算法是路径规划算法中’最好’的群智能算法。快让我们开始吧&#xff01; 目录1. 蚁群算法基本介绍1.1 算法简介1.2 算法原理2.蚁群算法的基本流程2.1 路径构建2.2 蚂蚁信息素的更新3. scik…

使用POI和EasyExcel实现Excel导入和导出功能

需求场景 开发中经常会设计到excel的处理&#xff0c;需求场景如下所示&#xff1a; 1、将用户信息导出为excel表格&#xff08;导出数据&#xff09; 2、将Excel表中的信息录入到数据库中&#xff08;导入数据&#xff09; 操作Excel目前比较流行的就是 Apache POI 和 阿里…

单片机通过WIFI模块(ESP8266)获取网络时间与天气预报

前几天发布了开源4.3寸触摸屏的文章 《开源4.3寸触摸屏》&#xff0c;里面有WIFI获取时间和天气预报相关的功能&#xff0c;今天就来介绍一下这个功能是怎样实现的。 1.底层驱动 首先&#xff0c;硬件上&#xff0c;单片机通过串口AT指令访问WIFI模块&#xff08;ESP12S&#x…

有营养的算法笔记(七)

字符串消除 1.题目描述 给定一个只由’a’和’b’组成的字符串str&#xff0c;str中"ab"和"ba"子串都可以消除&#xff0c; 消除之后剩下字符会重新靠在一起&#xff0c;继续出现可以消除的子串…你的任务是决定一种消除的顺序&#xff0c;最后让str消除到…

(附源码)计算机毕业设计SSM基于人脸识别和测温的宿舍管理系统

&#xff08;附源码&#xff09;计算机毕业设计SSM基于人脸识别和测温的宿舍管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09…

Redis 集群安装-Centos

Redis 集群安装-Centos Redis3.0以后的版本虽然有了集群功能&#xff0c;提供了比之前版本的哨兵模式更高的性能与可用性&#xff0c;但是集群的水平扩展却比较麻烦&#xff0c;今天就来带大家看看redis高可用集群如何做水平扩展&#xff0c;原始集群(见下图)由6个节点组成&am…

【图灵MySQL】MySQL索引优化实战(上)

【图灵MySQL】MySQL索引优化实战&#xff08;上&#xff09; 数据准备-SQL CREATE TABLE employees (id int(11) NOT NULL AUTO_INCREMENT,name varchar(24) NOT NULL DEFAULT COMMENT 姓名,age int(11) NOT NULL DEFAULT 0 COMMENT 年龄,position varchar(20) NOT NULL DEF…

1024程序员节带你玩转图片Exif信息获取之JavaScript

目录 一、前言 二、背景 三、Exif.js 1、Exif.js 简介 2、Exif.js 引入 四、多场景展示数据获取 1、原始图片直接获取 2、base64 编码文件加载 3、文件上传的方式加载 五、总结 一、前言 1024是2的十次方&#xff0c;二进制计数的基本计量单位之一。1G1024M&#xff0c;而…

git工具基本操作命令

初始化 首先在某个文件下新建一个项目。然后使用git初始化命令开始正式管理写好的代码。 首先新建一个项目&#xff1a; 然后在上述文件夹中右键选择git&#xff0c;或者直接在该文件路径下打开cmd进行操作&#xff1a; 上述操作出现了.git文件夹&#xff0c;今后所有的操作都…

Sharding-JDBC实现读写分离

前言 快一个月没有更新文章了&#xff0c;太忙了太忙了&#xff0c;虽然慢了一点&#xff0c;但是我肯定不会断更。上一篇文章是《Mysql主从复制》&#xff0c;光是数据库层面的主从复制可不行&#xff0c;应用层面也是需要读写分离的&#xff0c;所以接上一篇文章我们来讲如何…

赶紧进来看看---万字博客详解C/C++中的动态内存管理

本篇博客主要介绍了C/C程序内部的内存开辟.动态内存分布 动态内存函数malloc calloc realloc free的使用 常见的动态内存错误.以及柔性数组的概念与使用 学会动态内存管理将不再局限于使用静态的空间,对内存空间的理解和使用将更进一层楼~ C/C动态内存管理一.认识C/C程序的内存…

【C++升级之路】类与对象(中)

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【C学习与应用】 ✒️✒️本篇内容&#xff1a;类与对象知识汇总&#xff0c;包括6大默认成员函数、日期类的实现 &#x1f6a2;&#x1f6a2;作者简介&…

graphQL入门分享

是什么 一种用于 API 的查询语言&#xff1b;它与特定技术无关&#xff0c;你可以用任何语言实现它 简单理解&#xff0c;他能提供一个接口&#xff0c;让我们来调用&#xff0c;只是返回的数据格式更多是由我们前端来控制 为什么 官网&#xff1a;https://graphql.cn/ 1.请求你…