龙空技术网

轻松掌握MATLAB - 2.4 数组的内存管理与矩阵思想

junziyang 47

前言:

而今你们对“matlab访问数组元素”都比较重视,姐妹们都需要分析一些“matlab访问数组元素”的相关资讯。那么小编在网上搜集了一些关于“matlab访问数组元素””的相关内容,希望咱们能喜欢,咱们一起来学习一下吧!

上一篇:轻松掌握MATLAB - 2.3 数组的索引与变换2.4.1 数组的内存管理

在MATLAB中,数值型数组在内存中是连续存储的。MATLAB会为每个数组分配一块连续的内存空间,并按照列优先的原则将数组的元素依次存入内存单元。一旦数组的大小发生变化,MATLAB 就会重新分配一块适合新数组的内存,将数据复制过去,并释放原来数组占用的内存。在程序运行过程中,如果数组的大小不断变化,MATLAB 就会频繁地进行内存分配和回收,这将严重影响程序的运行效率。因此,尽管 MATLAB 并不要求用户主动管理内存,对于较大的数组,我们应该养成提前为其分配内存的习惯,以避免因数组在程序中不断“长大”而影响程序的运行效率

如我们在第一章中所述,最初版本的 MATLAB 是基于 Fortran 语言开发的,因此它继承了 Fortran 语言中 “列优先” 存储数组的习惯。在MATLAB中对数组进行存取操作时,为了充分利用计算机的缓存机制,避免因在内存中四处寻址造成的效率损失,应按照“列优先”的顺序来对数组进行索引和修改。

下面我们通过一个例子,来直观的比较一下上述两条原则对数组访问效率的影响。如下代码将创建一个r行c列的矩阵M,M中的元素等于其所在位置的行、列坐标之和。程序比较了不预分配内存且行优先、不予分配内存且列优先、预分配内存且行优先,以及预分配内存且列优先这四种情况下程序完成相同工作的耗时。在Editor中录入如下代码并保存为compareArrayIndexing.m,然后点击Editor工具栏上的Run按钮运行程序。可以修改变量r和c的值,反复运行compareArrayIndexing.m,观察对不同大小的数组这4种方法的区别程度。体会MATLAB中使用数组的要点。

clear r = 5000; %数组的行数,根据需要修改c = 5000; %数组的列数,根据需要修改%% ---------------------------------------不预分配内存ticfor m=1:r %行优先    for n=1:c        M(m,n) = m+n;    endendfprintf('未预分配内存,行优先耗时%f s\n',toc)clear M %清除变量,回收内存ticfor n=1:c %列优先    for m=1:r        M(m,n) = m+n;    endendfprintf('未预分配内存,列优先耗时%f s\n',toc)clear M %清除变量,回收内存%% ---------------------------------------预分配内存ticM = zeros(r,c);  %预分配内存for m=1:r %行优先    for n=1:c        M(m,n) = m+n;    endendfprintf('预分配内存,行优先耗时%f s\n',toc)clear M %清除变量,回收内存ticM = zeros(r,c); %预分配内存for n=1:c %列优先    for m=1:r        M(m,n) = m+n;    endendfprintf('预分配内存,列优先耗时%f s\n',toc)

上图所示是在r和c均为5000时的运行结果。可以看出,预分配内存且列优先的情况下,耗时是最少的。而未预分配内存且行优先情况下,则耗时最多。后者的耗时是前者的900多倍!计算机的硬件配置不同,每种方法消耗的具体时间可能不同,但结论是一致的:为大数组预分配内存,并遵循MATLAB的“列优先”原则来存取数组,可以显著提高程序的运行效率。数组越大,效果越明显。

【说明】

for是MATLAB的循环语句之一,它通过用循环变量index按列遍历一个数组loopArray,反复执行介于for和end之间statements。循环的总次数等于size(loopArray,2)。其基本语法如下:

for index = loopArray			statementsend
tic和toc是MATLAB用来计时的两个函数,就像秒表的“滴答”声,tic开始计时,toc停止计时。“拙匠常怪工具差”!MATLAB编程中除了算法方面的原因外,绝大多少效率问题都是因“内存使用不当”造成的!2.4.2 矩阵思想与代码向量化

与其他语言(如c语言)中基于循环且面向标量的运算方式不同,MATLAB中绝大部分数值计算相关的内置函数和所有的算术运算符都支持直接对矩阵进行运算,特别是底层的函数库都针对涉及矩阵和向量的运算进行了深度的优化。因此,在MATLAB中进行编程时,将矩阵视为基本数据单元,基于矩阵和向量来思考问题,从而摆脱掉不必要的循环,才能最大程度的发挥MATLAB的优势。这种编程思路称为矩阵思想。按矩阵思想编写的代码称为向量化代码(Vectorized code)或矩阵化代码。遵循矩阵思想编程可以带来诸多好处:

代码容易理解。向量化代码与教科书上的数学表达式高度一致,这使得代码易读、易理解。由于摆脱了循环,代码更简短,不易出错。运行效率高。向量化代码往往比循环执行效率要高。

例如,分别用标量化和矢量化代码计算一个向量x的正弦:

%% 标量化的代码ticm = 0;for x = 0:pi/1000:2*pi    m = m+1;    y(m) = sin(x);endt1 = toc;%% 向量化代码ticx = 0:pi/1000:2*pi;y = sin(x); t2 = toc;fprintf('矢量化后代码运行速度提高了%.2f倍。\n',t1/t2)

上述标量化的代码中,需要使用一个循环将向量x的各个元素逐一传递给sin函数进行计算,而向量化的代码则将向量x作为一个整体传递给了sin函数。显然,基于矩阵思想的代码更简洁、高效和易于理解。MATLAB 的sin函数不仅支持向量,即使将矩阵,甚至是多维数组直接传递给它,也可以直接得到计算结果。

MATLAB的加+、减-、点乘.*、点除./和点乘方.^也都是向量化算符,它们对“兼容数组”进行对应元素运算。例如,

上述3行代码将全1矩阵a的每一列依次增加了1。若用循环思想,需要两重循环,逐个元素操作。而用矩阵思想,只需创建另一个矩阵,一次性完成。

类似的,将a逐列乘数增加1:

算符*和/分别用于矩阵相乘和相除。需要注意的是,这两个算符不是向量化的算符,必须满足矩阵的运算规则,否则MATLAB会报错。例如,

从报错信息可以看出,报错的原因在于a和b不满足矩阵乘法的条件:第一个矩阵的列数等于第二个矩阵的行数。

【说明】

向量化的函数和算符虽然也支持多维数组,但在处理多维数组时效率会比矩阵低一些,特别是在多维数组比较大的情况下。这主要是内存管理导致的效率损失。在编程过程中,要养成使用.*./.^的习惯,只有在涉及真正的矩阵运算时才使用*、/和^算符。这样有利于提高代码的向量化程度和运行效率。关于MATLAB的运算符,将在第四章中详细介绍。思考与练习辨析MATLAB中的几个概念:数组、矩阵、向量、标量?空数组的维度是0吗,如何查询其维度?生成一个3x4元素均10的矩阵,你能想到几种方法?已知A = magic(5),将A中小于10的元素设置为0。已知A = magic(5),如何将A中所有的元素都从小到大排列?常用的索引数组元素的方法有哪几种?一般来说哪种方法效率最高?在命令行doc sort,然后点击帮助文档上方的Functions,可以列出MATLAB提供的矩阵与数组相关的函数。本节已经演示了其中部分函数的常见用法。了解这些函数及其基本功能,以备不时之需。本章的示例程序compareArrayIndexing.m中,为了演示不同数组存取方法的效率,代码是采用的是循环思想编写的。思考一下,基于矩阵思想如何创建满足同样要求的矩阵M?

下一篇: 轻松掌握MATLAB - 3.1 MATLAB的基本数据类型(1)

标签: #matlab访问数组元素 #matlab怎么设置内存