提高matlab代码运行效率

上传人:沈*** 文档编号:194654674 上传时间:2023-03-13 格式:PDF 页数:16 大小:1.11MB
返回 下载 相关 举报
提高matlab代码运行效率_第1页
第1页 / 共16页
提高matlab代码运行效率_第2页
第2页 / 共16页
提高matlab代码运行效率_第3页
第3页 / 共16页
点击查看更多>>
资源描述
提高 matlab 代码运行效率 Matlab 是一种解释性语言,追求的是方便性、灵活性以及交互性,因此在快速性上要比 C 语言这种性能强劲著称的稍逊一筹。然而,通过一些手段,我们也能让 MATLAB 语言快起来,甚至和 C 差不多了!1 可行方法 1.1 循环矢量化 MATLAB 变量的基本类型是矩阵,当对矩阵的每个元素循环处理时,运算速度很慢。利用 MATLAB 提供的用于矢量化操作的函数,把循环矢量化,这样既可以提高编程效率,也可以提高程序的执行效率。下面给出一个循环的例子:i=0;for n=0:0.1:1000 I=i+1;y(i)=cos(n);end 那么我们可以矢量化为:n=0:0.1:1000;y=cos(n);我们可以用 tic 和 toc 函数来查看上述各代码运行的时间,可以发现,把数组看作一个整体,进行操作后,执行效率提高约 300 倍。另外,在必须使用多重循环的情况下,建议在循环的外环执行循环次数少的,内环执行循环次数多的,这样也可以显著提高程序执行速度。下面再举一个例子 n=100;A(1:1000,1:1000)=13;C(1:1000,1)=15;D(1:1000,1)=0;for k=1:n D(:)=0;tic for i=1:1000 for j=1:1000 D(i)=D(i)+A(i,j)*C(j);end end t1(k)=toc;%-D(:)=0;tic D=A*C;t2(k)=toc;end u=t1./t2;u(u0)=;plot(u)p=mean(u)t1、t2 分别代表用 for 循环编程和矩阵化编程计算矩阵乘向量所用时间,u 代表时间的比值。u(u109)=;t1(t1109)=;plot(t1;t2)t1、t2 分别表示预先分配空间和循环中分配空间的时间,下图上面一条 t2、一条 t1 1.8 内存管理函数和命令 1)Clear variablename:从内存中删除名称为 variablename 的变量。2)Clear all:从内存中删除所有的变量。3)Save:将指令的变量存入磁盘。4)Load:将 save 命令存入的变量载入内存。5)Quit:退出 MATLAB,并释放所有分配的内存。6)Pack:把内存中的变量存入磁盘,再用内存中的连续空间载回这些变量。考虑到执行效率问题,不能在循环中使用。1.9 节约内存的方法 1)避免生成大的中间变量,并删除不再需要的临时变量。2)当使用大的矩阵变量时,预先指定维数并分配好内存,避免每次临时扩充维数。3)当程序需要生成大量变量数据时,可以考虑定期将变量写到磁盘,然后清除这些变量。当需要这些变量时,再重新从磁盘加载。4)当矩阵中数据极少时,将全矩阵转换为稀疏矩阵。1.10 其他经验 1)多重循环让内层循环次数多 在必须使用多重循环时下,如果两个循环执行的次数不同,则在循环的外环执行循环次数少的,内环执行循环次数多的,这样可以提高速度。n=1000;A=ones(1000)*13;for k=1:n tic for i=1:10 for j=1:1000 A(i,j)=A(i,j)*15;end end t1(k)=toc;tic for i=1:1000 for j=1:10 A(i,j)=A(i,j)*16;end end t2(k)=toc;end t2(t1109)=;t1(t1109)=;t1(t2109)=;t2(t2109)=;%去除外界因素影响所产生的寄点 plot(1:size(t1,2),t1,r,1:size(t1,2),t2)由这个时间图可以看出 for 循环的嵌套顺序对于速度是有影响的,虽然相对来说差别不是很大。2.Performance Acceleration 关于什么是“Performance Acceleration”请参阅 matlab 的帮助文件。我只简要的将其规则总结如下 7 条:1)只有使用以下数据类型,matlab 才会对其加速:logical,char,int8,uint8,int16,uint16,int32,uint32,double 而语句中如果使用了非以上的数据类型则不会加速,如:numeric,cell,structure,single,function handle,java classes,user classes,int64,uint64 2)matlab 不会对超过三维的数组进行加速。3)当使用 for 循环时,只有遵守以下规则才会被加速:a、for 循环的范围只用标量值来表示;b、for 循环内部的每一条语句都要满足上面的两条规则,即只使用支持加速的数据类型,只使用三维以下的数组;c、循环内只调用了内建函数(build-in function)。4)当使用 if、elseif、while 和 switch 时,其条件测试语句中只使用了标量值时,将加速运行。5)不要在一行中写入多条操作,这样会减慢运行速度。即不要有这样的语句:x=a.name;for k=1:10000,sin(A(k),end;6)当某条操作改变了原来变量的数据类型或形状(大小,维数)时将会减慢运行速度。7)应该这样使用复常量 x=7+2i,而不应该这样使用:x=7+2*i,后者会降低运行速度。”8)“尽量用向量化的运算来代替循环操作。最常用的使用 vectorizing 技术的函数有:All、diff、ipermute、permute、reshape、ueeze、y、find、logical、prod、shiftdim、sub2ind、cumsum、ind2sub、ndgrid、repmat、sort、sum 等。”优先使用 matlab 内建函数,将耗时的循环编写进 MEX-File 中以获得加速。3.MATLAB 代码矢量化指南 这里列出了MATLAB 代码矢量化指南(译)3.1 基本技术 1)MATLAB 索引或引用 在 MATLAB 中有三种基本方法可以选取一个矩阵的子阵。它们分别是下标法,线性法和逻辑法(subscripted,linear,and logical)。如果你已经熟悉这个内容,请跳过本节 1、下标法 非常简单,看几个例子就好。A=6:12;A(3,5)ans=8 10 A(3:2:end)ans=8 10 12 A=11 14 17;12 15 18;13 16 19;A(2:3,2)ans=15 16 2、线性法 二维矩阵以列优先顺序可以线性展开,可以通过现行展开后的元素序号 来访问元素。A=11 14 17;12 15 18;13 16 19;A(6)ans=16 A(3,1,8)ans=13 11 18 A(3;1;8)ans=13 11 18 3、逻辑法 用一个和原矩阵具有相同尺寸的 0-1 矩阵,可以索引元素。在某个位置上为 1 表示选取元素,否则不选。得到的结果是一个向量。A=6:10;A(logical(0 0 1 0 1)ans=8 10 A=1 2 3 4;B=1 0 0 1;A(logical(B)ans=1 4 2)数组操作和矩阵操作 对矩阵的元素一个一个孤立进行的操作称作数组操作;而把矩阵视为一个整体进行的运算则成为矩阵操作。MATLAB 运算符*,/,都是矩阵运算,而相应的数组操作则是.*,./,.,.A=1 0;0 1;B=0 1;1 0;A*B%矩阵乘法 ans=0 1 1 0 A.*B%A 和 B 对应项相乘 ans=0 0 0 0 3)布朗数组操作 对矩阵的比较运算是数组操作,也就是说,是对每个元素孤立进行的。因此其结果就不是一个“真”或者“假”,而是一堆“真假”。这个结果就是布朗数组。D=-0.2 1.0 1.5 3.0-1.0 4.2 3.14;D=0 ans=0 1 1 1 0 1 1 如果想选出 D 中的正元素:D=D(D0)D=1.0000 1.5000 3.0000 4.2000 3.1400 除此之外,MATLAB 运算中会出现 NaN,Inf,-Inf。对它们的比较参见下例 Inf=Inf 返回真 Inf 用于计算数组的双重 for 循环。使用的工具:数组乘法 优化前:A=magic(100);B=pascal(100);for j=1:100 for k=1:100;X(j,k)=sqrt(A(j,k)*(B(j,k)-1);end end 优化后:A=magic(100);B=pascal(100);X=sqrt(A).*(B-1);用一个循环建立一个向量,其元素依赖于前一个元素使用的工具:FILTER,CUMSUM,CUMPROD 优化前:A=1;L=1000;for i=1:L A(i+1)=2*A(i)+1;end 优化后:L=1000;A=filter(1,1-2,ones(1,L+1);如果你的向量构造只使用加法或乘法,你可使用 cumsum 或 cumprod 函数。优化前:n=10000;V_B=100*ones(1,n);V_B2=100*ones(1,n);ScaleFactor=rand(1,n-1);for i=2:n V_B(i)=V_B(i-1)*(1+ScaleFactor(i-1);end for i=2:n V_B2(i)=V_B2(i-1)+3;end 优化后:n=10000;V_A=100*ones(1,n);V_A2=100*ones(1,n);ScaleFactor=rand(1,n-1);V_A=cumprod(100 1+ScaleFactor);V_A2=cumsum(100 3*ones(1,n-1);向量累加,每 5 个元素进行一次:工具:CUMSUM,向量索引 优化前:%Use an arbitrary vector,x x=1:10000;y=;for n=5:5:length(x)y=y sum(x(1:n);end 优化后(使用预分配):x=1:10000;ylength=(length(x)-mod(length(x),5)/5;%Avoid using ZEROS command during preallocation y(1:ylength)=0;for n=5:5:length(x)y(n/5)=sum(x(1:n);end 优化后(使用矢量化,不再需要预分配):x=1:10000;cums=cumsum(x);y=cums(5:5:length(x);操作一个向量,当某个元素的后继元素为 0 时,重复这个元素:工具:FIND,CUMSUM,DIFF 任务:我们要操作一个由非零数值和零组成的向量,要求把零替换成为它前面的非零数值。例如,我们要转换下面的向量:a=2;b=3;c=5;d=15;e=11;x=a 0 0 0 b 0 0 c 0 0 0 0 d 0 e 0 0 0 0 0;为:x=a a a a b b b c c c c c d d e e e e e e;解(diff 和 cumsum 是反函数):valind=find(x);x(valind(2:end)=diff(x(valind);x=cumsum(x);将向量的元素累加到特定位置上 工具:SPARSE 优化前:%The values we are summing at designated indices values=20 15 45 50 75 10 15 15 35 40 10;%The indices associated with the values are summed cumulatively indices=2 4 4 1 3 4 2 1 3 3 1;totals=zeros(max(indices),1);for n=1:length(indices)totals(indices(n)=totals(indices(n)+values(n);end 优化后:indices=2 4 4 1 3 4 2 1 3 3 1;totals=full(sparse(indices,1,values);注意:这一方法开辟了稀疏矩阵的新用途。在使用 sparse 命令创建稀疏矩阵时,它是对分配到同一个索引的所有值求和,而不是替代已有的数值。这称为向量累加,是 MATLAB处理稀疏矩阵的方式。4.建议 对于撰写高效 MATLAB 代码,我有下面一些建议:1.虽然 for-loop 的速度有了很大改善,vectorization(向量化)仍旧是改善效率的重要途径,尤其是在能把运算改写成矩阵乘法的情况下,改善尤为显著。2.在不少情况下,for-loop 本身已经不构成太大问题,尤其是当循环体本身需要较多的计算的时候。这个时候,改善概率的关键在于改善循环体本身而不是去掉 for-loop。3.MATLAB 的函数调用过程(非 built-in function)有显著开销,因此,在效率要求较高的代码中,应该尽可能采用扁平的调用结构,也就是在保持代码清晰和可维护的情况下,尽量直接写表达式和利用 built-in function,避免不必要的自定义函数调用过程。在次数很多的循环体内(包括在 cellfun,arrayfun 等实际上蕴含循环的函数)形成长调用链,会带来很大的开销。4.在调用函数时,首选 built-in function,然后是普通的 m-file 函数,然后才是 function handle 或者 anonymous function。在使用 function handle 或者 anonymous function 作为参数传递时,如果该函数被调用多次,最好先用一个变量接住,再传入该变量。这样,可以有效避免重复的解析过程。5.在可能的情况下,使用numeric array或者struct array,它们的效率大幅度高于cell array(几十倍甚至更多)。对于 struct,尽可能使用普通的域(字段,field)访问方式,在非效率关键,执行次数较少,而灵活性要求较高的代码中,可以考虑使用动态名称的域访问。6.虽然 object-oriented 从软件工程的角度更为优胜,而且 object 的使用很多时候很方便,但是MATLAB 目前对于OO的实现效率很低,在效率关键的代码中应该慎用objects。7.如果需要设计类,应该尽可能采用普通的 property,而避免灵活但是效率很低的dependent property。如非确实必要,避免重载 subsref 和 subsasgn 函数,因为这会全面接管对于 object 的接口调用,往往会带来非常巨大的开销(成千上万倍的减慢),甚至使得本来几乎不是问题的代码成为性能瓶颈。
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!