c++中大矩阵乘法计算的效率问题
假设两个大小相同的方阵需要计算乘法:按照矩阵乘法的规则:
先写一段矩阵初始化代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;void matrix_print(int **a, int n);int main(int argc, char *argv[])
{// 定义数组:srand(time(0));int matrix_n = 10;int numberOfRows = matrix_n;int numberOfCols = matrix_n;int** mat1 = new int* [numberOfRows]; // a矩阵的行数int** mat2 = new int* [numberOfRows]; int** mat3 = new int* [numberOfRows]; for(int i=0; i<numberOfRows; i++){mat1[i] = new int[numberOfCols];mat2[i] = new int[numberOfCols];mat3[i] = new int[numberOfCols];} // 初始化矩阵 1-10之间的随机数 for(int i=0; i<numberOfRows; i++){for(int j=0; j<numberOfCols; j++){mat1[i][j] = 1 + rand()%(10-1+1);mat2[i][j] = 1 + rand()%(10-1+1);}}matrix_print(mat1, matrix_n); // 输出矩阵 matrix_print(mat2, matrix_n); // 输出矩阵 //matrix_print(mat3, matrix_n);return 0;
}// 输出矩阵
void matrix_print(int **a, int n)
{for(int i=0; i<n; i++){for(int j=0; j<n; j++){cout << a[i][j] << " ";}cout << endl;}cout << endl;
}
初步测试:
现在将矩阵乘法的循环的潜逃次序改变一下,改写为一个新的函数,两个函数对比如下:
1.matrix_multiply_ijk版本:
// 计算矩阵乘法 ijk
void matrix_multiply_ijk(int **a, int **b, int **c, int n) // n表示方阵的阶数
{for(int i=0; i<n; i++){for(int j=0; j<n; j++){int sum = 0;for(int k=0; k<n; k++){sum += a[i][k]*b[k][j];}c[i][j] = sum;}}
}
2.matrix_multiply_ikj版本:
// 计算矩阵乘法 ikj
void matrix_multiply_ikj(int **a, int **b, int **c, int n) // n表示方阵的阶数
{for(int i=0; i<n; i++){for(int k=0; k<n; k++){int sum = 0;int j;for(j=0; j<n; j++){sum += a[i][k]*b[k][j];}c[i][j] = sum;}}
}
性能测量:
3.通过在不同的维度下测试两个函数的运行时间:
c++测试代码运行时间的方法:通过像个的时钟数来测量;
在ijk的方法下:
1st | 2nd | 3rd | 4th | |
n=100 | 6 | 3 | 7 | 4 |
n=300 | 104 | 90 | 95 | 92 |
n=500 | 474 | 492 | 484 | 469 |
n=800 | 2001 | 2100 | 2170 | 2042 |
n=1200 | 10615 | 9821 | 9689 | 9703 |
n=2000 | 63677 | 62797 | 62698 | 62551 |
在ikj的方法下:
1st | 2nd | 3rd | 4th | |
n=100 | 5 | 3 | 3 | 3 |
n=300 | 77 | 79 | 81 | 78 |
n=500 | 328 | 351 | 341 | 359 |
n=800 | 1435 | 1413 | 1423 | 1453 |
n=1200 | 4901 | 4778 | 4849 | 4694 |
n=2000 | 21664 | 21501 | 21968 | 21947 |
结论:
可以看到。在ikj的方案下,矩阵乘法的运算速度较快,而且在矩阵阶数n越大的时候,这种差别越是明显。在计算矩阵乘法的过程中,三层的循环嵌套共有六种排列方式,虽然在每种嵌套方式下,都要执行同样数量的操作,但是花费的时间是不同的。这是因为在不同的嵌套方式下,改变了数据的访问模式,进而改变了缓存未命中的数量。最终影响了运行时间。
关于缓存未命中的简单理解:
简单计算机模型:
L1 一级缓存
L2二级缓存
R 寄存器
ALU算术逻辑单元
在程序开始运行时,数据都位于主存中,需要将参与运算的数据从主存移到寄存器再进行运算。如果需要的数据没有在一级缓存,而是在二级缓存,而需要将数据存二级缓存移动到一级缓存,这称为一级缓存未命中,当需要的数据没有在二级缓存中时,此时为二级缓存未命中,则需要将数据从主存移动到二级缓存,再移动到一级缓存。所以可以通过减少缓存未命中的数量,提高程序的运行效率。计算机会采取相应的策略。
完整代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <time.h> // 包含时间测量的函数
using namespace std;void matrix_multiply_ijk(int **a, int **b, int **c, int n);
void matrix_multiply_ikj(int **a, int **b, int **c, int n);void matrix_print(int **a, int n);int main(int argc, char *argv[])
{// 定义数组:srand(time(0));int matrix_n = 2000; // 修改矩阵的阶数为不同的值 int numberOfRows = matrix_n;int numberOfCols = matrix_n;int** mat1 = new int* [numberOfRows]; // a矩阵的行数int** mat2 = new int* [numberOfRows]; int** mat3 = new int* [numberOfRows]; for(int i=0; i<numberOfRows; i++){mat1[i] = new int[numberOfCols];mat2[i] = new int[numberOfCols];mat3[i] = new int[numberOfCols];} // 初始化矩阵 1-10之间的随机数 for(int i=0; i<numberOfRows; i++){for(int j=0; j<numberOfCols; j++){mat1[i][j] = 1 + rand()%(10-1+1);mat2[i][j] = 1 + rand()%(10-1+1);}}//matrix_print(mat1, matrix_n); // 输出矩阵 //matrix_print(mat2, matrix_n); // 输出矩阵 //matrix_print(mat3, matrix_n);double clocks_PerMills = double(CLOCKS_PER_SEC) / 1000.0; // 常数,每秒钟包含的时钟数 clock_t start_time = clock(); // 开始的时钟数 // 选择矩阵乘法方案 //matrix_multiply_ijk(mat1, mat2, mat3, matrix_n); // 矩阵乘法matrix_multiply_ikj(mat1, mat2, mat3, matrix_n);double elapseMills = (clock()-start_time) / clocks_PerMills; cout << "The routine run time: " << elapseMills << "ms" << endl;cout << "clock_perMils: " << clocks_PerMills << endl; //matrix_print(mat3, matrix_n);// matrix_multiply_ikj(mat1, mat2, mat3, matrix_n);// matrix_print(mat3, matrix_n);// 释放内存 for(int i=0; i<numberOfRows; i++){delete mat1[i];delete mat2[i];delete mat3[i];}delete mat1;delete mat2;delete mat3;return 0;
}// 计算矩阵乘法 ijk
void matrix_multiply_ijk(int **a, int **b, int **c, int n) // n表示方阵的阶数
{for(int i=0; i<n; i++){for(int j=0; j<n; j++){int sum = 0;for(int k=0; k<n; k++){sum += a[i][k]*b[k][j];}c[i][j] = sum;}}
}// 计算矩阵乘法 ikj
void matrix_multiply_ikj(int **a, int **b, int **c, int n) // n表示方阵的阶数
{for(int i=0; i<n; i++){for(int k=0; k<n; k++){int sum = 0;int j;for(j=0; j<n; j++){sum += a[i][k]*b[k][j];}c[i][j] = sum;}}
}// 输出矩阵
void matrix_print(int **a, int n)
{for(int i=0; i<n; i++){for(int j=0; j<n; j++){cout << a[i][j] << " ";}cout << endl;}cout << endl;
}
----------------------------------------------------end--------------------------------------------------------
c++中大矩阵乘法计算的效率问题相关推荐
- 矩阵乘法计算速度再次突破极限,我炼丹能更快了吗?| 哈佛、MIT
梦晨 发自 凹非寺 量子位 报道 | 公众号 QbitAI n阶矩阵乘法最优解的时间复杂度再次被突破,达到了. 按定义直接算的话,时间复杂度是O(n³). 光这么说可能不太直观,从图上可以看出,n足够 ...
- HJ70 矩阵乘法计算量估算 ——
一.题目 二.代码 import java.util.*; public class Main {public static void main(String[] args) {Scanner in ...
- CUDA加速计算矩阵乘法进阶玩法(共享内存)
CUDA加速计算矩阵乘法&进阶玩法~共享内存 一.基础版矩阵乘法 二.为什么可以利用共享内存加速矩阵乘法 1.CUDA内存读写速度比较 2.申请共享内存 三.改进版矩阵乘法(利用共享内存) 一 ...
- 大数据Mapreduce编程——矩阵乘法
编程要求 完成矩阵乘法的 Map 函数和 Reduce 函数 1.设计两个矩阵(3050,50100),在每个单元格中填入一个 0-99 的随机数,并写入 两个文件中,作为 Map 函数的输入 2.测 ...
- DeepMind再登Nature封面!推出AlphaTensor:强化学习发现矩阵乘法算法
点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 转载自:机器之心 DeepMind 的 Alpha 系列 AI 智能体家族又多了一个成员--AlphaTen ...
- 【Android 应用开发】Paint 滤镜原理 之 颜色矩阵 ( 颜色模式 | 颜色通道 | 颜色矩阵 | 矩阵运算 | 矩阵乘法 | 矩阵加法 | 颜色矩阵深入解析 )
文章目录 颜色模式 颜色通道 Android 中的颜色矩阵 矩阵乘法运算 滤镜中的矩阵乘法运算 矩阵加法运算 滤镜中的矩阵乘法运算 滤镜运算原理 ( 总结 ) 实际滤镜理论示例 颜色模式 颜色模式 : ...
- c++矩阵作为函数输入变量_C++实现矩阵乘法
最近学习C++,做了一个矩阵乘法的练习.先说一下功能,输入两个矩阵A,B,大小自己定,换行用:表示(matlab的习惯).然后输出A*B的矩阵. 1.思路 首先,由于输入的矩阵维数是随机的,因此,我们 ...
- jzoj5223-B【矩阵乘法】
正题 题目大意 3∗33*33∗3的矩阵上每个格子都有机器人,每次可以向相邻格子移动或不动(一个格子上可以有多个机器人),求移动nnn次后每个格子上都有机器人的移动方案数. 解题思路 用矩阵乘法计算出 ...
- numpy 矩阵乘法_NumPy 运算规则总结
1. 问题 ndarray 是 NumPy 的基础元素,NumPy 又主要是用来进行矩阵运算的.那么具体来说,ndarray 是如何进行普通矩阵运算的呢? 2. 分析 首先,在矩阵用 +-*/ 这些常 ...
最新文章
- RabbitMQ简单队列模式
- maven国内镜像配置
- 【转】判断五张牌是不是一个顺子
- win10创建新账户_win10系统卸载自带应用软件的操作方法
- python内建函数是什么意思_python内建函数是什么意思
- 基于Token的身份验证——JWT
- mysql bit php,Bit Web Server (PHP,MySQL,PMA) 安卓WEB服务器
- .NET性能分析最佳实践之:如何找出使用过多内存的.NET代码(基础篇)
- CSND Markdown模板
- 非负矩阵分解小白入门
- 如何对多个文件夹进行重命名?这个方法可以批量修改文件夹名、给文件夹名加统一前缀或后缀
- 最新图片交替闪现效果代码
- 使用Python-OpenCV实时测量物体的尺寸大小(仅供参考)
- P02014026黄一洋————信息论问题回答
- java实现计算器_Java 实现简单计算器
- UltraEdit 多词搜索
- swagger2的全新UI组件Knife4j
- 【SqlServer系列】子查询
- Python PEP8规范整理
- CSW博客《摧毁真相:虚假新闻的猖獗泛滥》
热门文章
- k8s核心技术-Pod(健康检查)_健康检查的方式_以及pod崩溃后如何处理---K8S_Google工作笔记0023
- C#串口通信工作笔记0001---上位机开发_嵌入式_串口助手_收发数据开发
- FPGA工作笔记0001---FPGA简介-强大的逻辑资源和恐怖的IO并行处理能力
- Netty工作笔记0066---Netty核心模块内容梳理
- java面试要点005---git和svn的区别
- c语言复制二进制文件
- 杭电1495非常可乐
- 杭电2539点球大战
- Lua字符串及模式匹配
- boost学习之安装