《MATLAB专刊》——利用向量化编程提升MATLAB代码执行效率


为了阐明采用向量化编程思路对于MATLAB双重 f o r for for循环优化的效果,本文通过一个实例展示不同编程思路对于代码执行效率的影响( B站视频讲解版)。

1. 实验说明

试验组别:
分为双重循环、向量化编程(Repmat函数)、向量化编程(Meshgrid函数)、向量化编程(bsx函数)共四个组别,每个组别重复 10 10 10次。
测试规模:
从2500万到52500万,以间隔为125000为步长
测试环境:
硬件: Intel®Core™ i9-10940X 双核CPU@3.30GHz 3.31 GHz,128GB内存
软件:Windows 10 系统, MATLAB R2018a

2. 实验结果

图1 实验结果对比图
表1 实验结果
测试规模双重for循环用时(s)repmat函数用时(s)meshgrid函数用时(s)bsx函数用时(s)
25,000,0000.102±0.0110.107±0.0050.399±0.0240.044±0.001
150,000,0000.619±0.0340.608±0.0392.160±0.0340.257±0.038
275,000,0001.156±0.0401.115±0.0323.963±0.0410.473±0.033
400,000,0001.727±0.0451.606±0.0355.558±0.0350.688±0.033
525,000,0002.269±0.0212.117±0.0366.965±0.0380.903±0.033
  • 从图 1 1 1和表格 1 1 1可以看出,代码执行效率方面: m e s h g r i d 函 数 < 双 重 f o r 循 环 < r e m p a t 函 数 < b s x 函 数 meshgrid函数<双重for循环<rempat函数<bsx函数 meshgrid<for<rempat<bsx
  • b s x bsx bsx函数执行效率最高,几乎是 m e s h g r i d meshgrid meshgrid 6 − 10 6-10 610倍,是双重 f o r for for循环的两倍。令人感到意外的是,采用向量化编程的 r e p m a t repmat repmat并没有比双重 f o r for for循环快很多,在测试实验中,两者相差并不是很大(详细可参考表1的实验结果)。
  • 上层封装函数的执行效率显著低于底层函数,隐式运算的速度显著快于显式运算。

3. 源程序

本节附录了测试的源程序

3.1 绘图源程序

clc
clear all
close all
path = '\测试结果总表.xlsx'; % 文件路径
%% 1. 读取数据
sheetname = '测试结果'; % excel页名称
[number,txt,raw] = xlsread(path,sheetname);
d.scale = number(:,1); % 测试规模
%% 2. 绘图
close all
Mycolor = [57,157,81;
148,95,63;
34,88,161;
224,66,61]/255; % 绿棕蓝红
Mysize = [1.5;
    1.5;
    18]; % 线宽设置
% Mystyle = ['o';
% '^';
% 's';
% 'p'];
figure
for i = 1:4
    d.time = number(:,2*i); % 测试时长(s)
    d.var = number(:,2*i+1); % 均方差
    h =  errorbar(d.scale,d.time,d.var,'.-','Color',Mycolor(i,:),'LineWidth',2,...
        'MarkerSize',12);
%     set(h,'Marker',Mystyle(i));
    hold on
end
%% 3. 图表美化
set(gca,'LineWidth',Mysize(2),'FontSize',Mysize(3),'FontName','Arial')
xlabel('Scale','FontName','Arial','FontSize',Mysize(3)); % x标签
ylabel('Time (s)','FontName','Arial','FontSize',Mysize(3)); % y标签
legend({'dual for loop','repmat function','meshgrid  function','bsx function'},...
    'Interpreter','latex','location','NorthWest'...
    ,'FontName','Arial','FontSize',Mysize(3)-2) % 添加图例
% print(gcf,'-clipboard','-dmeta')
print(gcf,'-r600','-dpng','测试对比结果') % 保存图片到指定路径

3.2 测试源程序

双重for循环:

clc
clear all 
close all
%% 双重for循环
S = [1000:5000:25000];
ResultsWrite = zeros(length(S)^2,2); % 初始化,第一列-计算规模,第二列-计算时间(10次平均值),第三列均方差
flag = 0;
for k1 = 1:length(S)
    for k2 = 1:10
        flag = flag + 1; % 计数
        s = S(k1); t = 25000;
        %% 测试段-开始
        t0 = clock; % 获取当前系统时间
        E = zeros((s-1)*(t-1),1); % 初始化网格矩阵
        N = 0; % 网格计数
        for i = 1:s-1
            for j = 1:t-1
                N = N + 1; % 计数
                E(N) = (j-1)*(s-1) + i; % 单元编号
            end
        end
    ResultsWrite(flag,:) = [s*t,etime(clock,t0)]; % 程序运行时间
    %% 测试段-结束
    end
end
name = strcat('双重循环运行时间记录','.xlsx'); % 保存文件名
Results = sortrows(ResultsWrite,1); % 排序
regResult = reshape(Results,10,10); % 规整化
A = mean(regResult,1); % 求均值
B = std(regResult,0,1); % 求均方差
B1 = B';
B2 = B1(6:10); % 均方差列向量
finRes = [reshape(A,5,2),B2];
xlswrite(name,finRes);   % 保存文件为excel

repmat函数:

clc
clear all 
close all
%% 向量化编程(repmat函数)
S = [1000:5000:25000];
ResultsWrite = zeros(length(S)^2,2); % 初始化,第一列-计算规模,第二列-计算时间(10次平均值),第三列均方差
flag = 0;
for k1 = 1:length(S)
    for k2 = 1:10
        flag = flag + 1; % 计数
        s = S(k1); t = 25000;
        %% 测试段-开始
        t0 = clock; % 获取当前系统时间
        E = zeros((s-1)*(t-1),1); % 初始化网格矩阵
        I = [1:s-1]'; J = [1:t-1]'; % 向量化
        E = (s-1).*repmat((J-1),1,s-1) + repmat(I',t-1,1); % 单元编号
        ResultsWrite(flag,:) = [s*t,etime(clock,t0)]; % 程序运行时间
    %% 测试段-结束
    end
end
name = strcat('向量化编程(repmat)运行时间记录','.xlsx'); % 保存文件名
Results = sortrows(ResultsWrite,1); % 排序
regResult = reshape(Results,10,10); % 规整化
A = mean(regResult,1); % 求均值
B = std(regResult,0,1); % 求均方差
B1 = B';
B2 = B1(6:10); % 均方差列向量
finRes = [reshape(A,5,2),B2];
xlswrite(name,finRes);   % 保存文件为excel

Meshgrid函数:

clc
clear all 
close all
%% 向量化编程(meshgrid函数)
S = [1000:5000:25000];
ResultsWrite = zeros(length(S)^2,2); % 初始化,第一列-计算规模,第二列-计算时间(10次平均值),第三列均方差
flag = 0;
for k1 = 1:length(S)
    for k2 = 1:10
        flag = flag + 1; % 计数
        s = S(k1); t = 25000;
        %% 测试段-开始
        t0 = clock; % 获取当前系统时间
        E = zeros((s-1)*(t-1),1); % 初始化网格矩阵
        I = [1:s-1]'; J = [1:t-1]'; % 向量化
        E = (s-1)*meshgrid(J'-1,I)' + meshgrid(I,J); % 单元编号
        ResultsWrite(flag,:) = [s*t,etime(clock,t0)]; % 程序运行时间
    %% 测试段-结束
    end
end
name = strcat('向量化编程(meshgrid)运行时间记录','.xlsx'); % 保存文件名
Results = sortrows(ResultsWrite,1); % 排序
regResult = reshape(Results,10,10); % 规整化
A = mean(regResult,1); % 求均值
B = std(regResult,0,1); % 求均方差
B1 = B';
B2 = B1(6:10); % 均方差列向量
finRes = [reshape(A,5,2),B2];
xlswrite(name,finRes);   % 保存文件为excel

bsx函数:

clc
clear all 
close all
%% 向量化编程(bsx函数)
S = [1000:5000:25000];
ResultsWrite = zeros(length(S)^2,2); % 初始化,第一列-计算规模,第二列-计算时间(10次平均值),第三列均方差
flag = 0;
for k1 = 1:length(S)
    for k2 = 1:10
        flag = flag + 1; % 计数
        s = S(k1); t = 25000;
        %% 测试段-开始
        t0 = clock; % 获取当前系统时间
        E = zeros((s-1)*(t-1),1); % 初始化网格矩阵
        I = [1:s-1]'; J = [1:t-1]'; % 向量化
        E = bsxfun(@plus,(s-1).*(J-1),I'); % 单元编号
        ResultsWrite(flag,:) = [s*t,etime(clock,t0)]; % 程序运行时间
    %% 测试段-结束
    end
end
name = strcat('向量化编程(bsx函数)运行时间记录','.xlsx'); % 保存文件名
Results = sortrows(ResultsWrite,1); % 排序
regResult = reshape(Results,10,10); % 规整化
A = mean(regResult,1); % 求均值
B = std(regResult,0,1); % 求均方差
B1 = B';
B2 = B1(6:10); % 均方差列向量
finRes = [reshape(A,5,2),B2];
xlswrite(name,finRes);   % 保存文件为excel

4. 参考资料

MATLAB-基础画图meshgrid
matlab学习笔记 bsxfun函数
matlab函数之bsxfun
Optimizing matlab code which uses repmat
MATLAB编程(3)——MATLAB依次运行多个脚本.m文件
Matlab绘制误差棒图----errorbar函数的使用
【Matlab】如何绘制errorbar误差棒

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿呆591

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值