相见恨晚的Matlab编程小技巧(3)-程序运行太慢了咋解决——合理使用循环语句(1)

简介: 相信大家在使用matlab时候经常会收到程序运行太慢的困扰,当程序比较复杂时,常常需要很长时间等待。我有个朋友就是这样,每次debug都要很长时间,等着的时候就想耍会手机,结果耍完一抬头发现程序运行结束了,但时间已经过去半天了。        一般来说,程序运行太慢都是因为循环的存在,使用双层甚至多层循环会使得程序运行效率极低。这篇博客将重点介绍如何在Matlab中避免使用循环语句并提高程序效率。我们将深入讨论向量化运算、预分配空间和相关函数(cellfun、arrayfun和structfun等)的用法,同时配有详细的示例代码和解释,帮助大家更好地掌握这些技术和优化方法。

       相信大家在使用matlab时候经常会收到程序运行太慢的困扰,当程序比较复杂时,常常需要很长时间等待。我有个朋友就是这样,每次debug都要很长时间,等着的时候就想耍会手机,结果耍完一抬头发现程序运行结束了,但时间已经过去半天了。

       一般来说,程序运行太慢都是因为循环的存在,使用双层甚至多层循环会使得程序运行效率极低。这篇博客将重点介绍如何在Matlab中避免使用循环语句并提高程序效率。我们将深入讨论向量化运算、预分配空间和相关函数(cellfun、arrayfun和structfun等)的用法,同时配有详细的示例代码和解释,帮助大家更好地掌握这些技术和优化方法。

1.记录程序运行时间

       为了比较使用循环语句与否对程序运行时间的影响,我们需要用到matlab中的tic,toc语句,tic函数表示开始计时。执行tic语句后,程序就会记录下当前时间。接下来的代码运行时,而程序会在toc函数调用时输出自tic函数到当前时刻所经过的时间。例如:

tic    % 开始计时
% 模块代码
x = 1:10000000;
y = sin(x);
disp(y(1:10));
toc    % 打印出程序自tic调用以来经过的时间

image.gif

       运行结果:

image.gif

        如果你不想在命令行输出运行时间,也可以将程序运行时间存在变量中,避免在命令行输出,例如:

tic    % 开始计时
% 模块代码
x = 1:10^8;
y = sin(x);
time0=toc;    % 将程序自tic调用以来经过的时间存在变量time0中

image.gif

image.gif

2.向量化运算

       为了提高程序性能,我们可以使用向量化运算来避免循环,同时实现对向量中所有元素的操作。向量化运算是一种在Matlab中广泛使用的高效操作方式,它可以对整个向量或矩阵进行运算,而不需要使用循环。具体来说,向量化运算使用内部优化的编译器,通过单个指令完成多个元素的处理,因此能够大大提高程序的效率。在Matlab中,常用的向量化运算符包括 .*, ./, .^, .', .*,等。具体的用法如表1所示:

表1 向量化运算符号的用法

运算符 用法 说明
.* A .* B A 数组和 B 数组中对应元素逐个相乘
./ A ./ B A 数组和 B 数组中对应元素逐个相除
.^ A .^ B A 数组和 B 数组中对应元素逐个做幂运算
.* A .* B B 对应 A 的每一列进行元素相乘运算

       首先举一个简单的例子来介绍如何使用向量化运算来代替循环语句。假设有两个矩阵 x 和 y,都包含500×500×500个元素,现在你想将它们每个元素相乘,然后将乘积相加。如果如果使用循环语句,可以这样写代码:

tic
x=rand(500,500,500);
y=rand(500,500,500);
c = 0;
for k = 1:500
    for kk = 1:500
        for kkk = 1:500
            c = c + x(k,kk,kkk) * y(k,kk,kkk);
        end
    end
end
toc

image.gif

       运行时间需要11.25秒。

image.gif

       如果你使用向量化操作,代码会更加简单,运行时间也会更短:

tic
x=rand(500,500,500);
y=rand(500,500,500);
c = sum(x(:) .* y(:));
toc

image.gif

image.gif

        运行只要2.46秒,快了不止一点点,在这个例子中,x(:)和y(:)表示将矩阵x用一维向量的形式表示。x(:) .* y(:)表示将一维向量化之后的 x 和 y 中对应元素相乘,并得到一个新的向量化,然后使用 sum 函数对这个新向量求和,从而得到我们想要的结果。显然,使用向量操作代替循环,代码更简洁、更易读、更易扩展。当处理大型数据集时,向量操作也可以大大提高程序运行速度。

3.预分配空间

       大家在使用Matlab编程时应该都看到过类似这样的警告:

image.gif

       这是在Matlab中,如果你想把一个新的元素添加到数组中,并且数组的大小没有指定或无法确定时,Matlab会重新分配整个数组并复制现有元素,这个过程会导致程序效率下降。当我们不得不使用循环语句时,我们也需要在使用变量前预分配空间。如果我们想在循环中构建一个数组时,你可以在循环之前预先分配数组空间,然后在循环中直接修改数组元素。这样做可以大大减少程序的运行时间和内存消耗。例如:

tic
x=rand(2000,2000);
y=rand(2000,2000);
for k = 1:2000
    for kk = 1:2000
        c(k,kk) = x(k,kk) * y(k,kk);
    end
end
toc

image.gif

        上面的代码没有预分配内存,所需运行时间为4.45秒。如果在for循环之前初始化变量c,代码这样写:

tic
x=rand(2000,2000);
y=rand(2000,2000);
c=zeros(2000,2000);
for k = 1:2000
    for kk = 1:2000
        c(k,kk) = x(k,kk) * y(k,kk);
    end
end
toc

image.gif

image.gif

        运行时间变成了0.2秒。一个不起眼的变量初始化,可以让代码运行速率快这么多。所以,之后编程的过程中,只要遇到循环语句,一定要确保循环内部用到的变量都是预分配内存的。

       这篇博客就先介绍这两种比较常用的方法,还有另一种使用相关函数的方法,我们将在下一篇博客单独进行介绍。

相关文章
|
2月前
|
数据采集 安全 新能源
【节点边际电价】机组运行约束对机组节点边际电价的影响分析(Matlab代码实现)
【节点边际电价】机组运行约束对机组节点边际电价的影响分析(Matlab代码实现)
246 2
【节点边际电价】机组运行约束对机组节点边际电价的影响分析(Matlab代码实现)
|
3月前
|
存储 算法 网络架构
基于多目标粒子群优化算法的冷热电联供型综合能源系统运行优化(Matlab代码实现)
基于多目标粒子群优化算法的冷热电联供型综合能源系统运行优化(Matlab代码实现)
164 2
|
2月前
|
安全 调度
【火电机组、风能、储能】高比例风电电力系统储能运行及配置分析(Matlab代码实现)
【火电机组、风能、储能】高比例风电电力系统储能运行及配置分析(Matlab代码实现)
基于MATLAB的电力磁电机内的电磁场计算程序的GUI实现
基于MATLAB的电力磁电机内的电磁场计算程序的GUI实现
|
2月前
|
算法 调度 决策智能
【复现】同时考虑考虑孤岛与重构的配电网故障恢复运行策略(Matlab代码实现)
【复现】同时考虑考虑孤岛与重构的配电网故障恢复运行策略(Matlab代码实现)
|
2月前
|
人工智能 运维 供应链
碳交易机制下考虑需求响应的综合能源系统优化运行(Matlab代码实现)
碳交易机制下考虑需求响应的综合能源系统优化运行(Matlab代码实现)
|
2月前
|
机器学习/深度学习 运维 算法
【EI复现】一种建筑集成光储系统规划运行综合优化方法(Matlab代码实现)
【EI复现】一种建筑集成光储系统规划运行综合优化方法(Matlab代码实现)
|
2月前
|
存储 边缘计算 算法
【太阳能学报EI复现】基于粒子群优化算法的风-水电联合优化运行分析(Matlab代码实现)
【太阳能学报EI复现】基于粒子群优化算法的风-水电联合优化运行分析(Matlab代码实现)
|
2月前
|
机器学习/深度学习 供应链 算法
【考虑经济性的储能运行优化】储能的运行优化,以经济效益最大为目标,使用三种不同的方法求解储能最优运行策略(Matlab代码实现)
【考虑经济性的储能运行优化】储能的运行优化,以经济效益最大为目标,使用三种不同的方法求解储能最优运行策略(Matlab代码实现)
|
2月前
|
人工智能 供应链 新能源
电动汽车参与运行备用的能力评估及其仿真分析(Matlab代码实现)
电动汽车参与运行备用的能力评估及其仿真分析(Matlab代码实现)

热门文章

最新文章