登录论坛

查看完整版本 : [求助]用MATLAB来计算一些科学数据,但用FOR循环计算时发现速度太慢


sa7312
2008-07-20, 10:36
  各位大侠,我是一个处于偏僻山区的教育者,现在急用MATLAB来计算一些科学数据,但用FOR循环计算时发现速度太慢,不知道还有什么办法解决。请大侠们多多帮且我啊。太恩不言谢,兄弟就此拜托了。
  以下是我这个刚学MATLAM的阿呆(:cry:) 的计算程序,请大侠们帮看看并提出增加速度的方案,小的在这有礼了!
  k=0.1:0.0000005:0.91;
j=1;
for m=0.1:0.0000005:0.91
e0=8.85*10^(-12); p0=4*pi*10^(-7);c0=3*10^8;a=3*10^(-10);
na=sqrt(9.0);nb=sqrt(1);nc=sqrt(4);nd=sqrt(1.0);ng=sqrt(16);nh=1.0;
da=0.5*a;db=0.5*a;dc=0.5*a;dd=0.5*a;dg=0.5*a;dh=0.5*a;
g0=sqrt(e0/p0)*1;
ga=g0*na;gb=g0*nb;gc=g0*nc;gd=g0*nd;gg=g0*ng;gh=g0*nh;
sa=-na*pi*m;sb=-nb*pi*m;sc=-nc*pi*m;sd=-nd*pi*m;sg=-ng*pi*m;sh=-nh*pi*m;
A=[cos(sa),-i*sin(sa)/ga;-i*ga*sin(sa),cos(sa)];B=[cos(sb),-i*sin(sb)/gb;-i*gb*sin(sb),cos(sb)];
C=[cos(sc),-i*sin(sc)/gc;-i*gc*sin(sc),cos(sc)];D=[cos(sd),-i*sin(sd)/gd;-i*gd*sin(sd),cos(sd)];
G=[cos(sg),-i*sin(sg)/gg;-i*gg*sin(sg),cos(sg)];H=[cos(sh),-i*sin(sh)/gh;-i*gh*sin(sh),cos(sh)];
M1=(G*H)^(5)*(A*B)^(5)*(C*D)^(5)*(B*A)^(5)*(H*G)^(5);
A1=M1(1,1);B1=M1(1,2);C1=M1(2,1);D1=M1(2,2);
r1=2*g0/(A1*g0+B1*g0^2+C1+D1*g0);
f1=r1*r1';
R1(1,j)=f1;
j=j+1;
end
plot(k,R1,'k');axis([0.1,0.9,0,1]),ylabel('Transmission');

mathjiang
2008-07-20, 12:24
循环次数达1620001次,的确慢。想快也快不起来

remnant
2008-07-21, 12:28
这个程序可以优化提速,等会儿给lz上程序,working...

sa7312
2008-07-21, 15:43
感谢Mathjiang,remnant大侠对小的支持!这个程序对于我,太重要了。谢谢!
                         初学者 顿首拜谢

tolabfans
2008-07-21, 16:16
听说写成向量形式代替循环比较快

sa7312
2008-07-21, 22:26
  我的本本电脑CPU主频是2.4,内存升级后为2.0G,在运行MATLAB程序的过程中出现如下提示符,该什么办?“??? Error using ==> plus
Out of memory. Type HELP MEMORY for your options.”
  恳请大侠们救救火哦,谢谢啦!
                   初学者 敬拜

remnant
2008-07-22, 14:46
  我的本本电脑CPU主频是2.4,内存升级后为2.0G,在运行MATLAB程序的过程中出现如下提示符,该什么办?“??? Error using ==> plus
Out of memory. Type HELP MEMORY for your options.”
  恳请大侠们救救火哦...
好,先上程序,边看边说。
%%
clear;
clc;
%%
t0 = cputime;

e0 = 8.85 * 10^(-12);
p0 = 4 * pi * 10^(-7);
c0 = 3 * 10^8;
a = 3 * 10^(-10);

na = sqrt( 9.0 );
nb = sqrt( 1 );
nc = sqrt( 4 );
nd = nb;
ng = sqrt( 16 );
nh = 1.0;

da = 0.5 * a;
db = da;
dc = da;
dd = da;
dg = da;
dh = da;

g0 = sqrt( e0/p0 );

ga = g0 * na;
gb = g0 * nb;
gc = g0 * nc;
gd = g0 * nd;
gg = g0 * ng;
gh = g0 * nh;

m = 0.1:0.0000005:0.91;
m_size = length( m );

sa = -1 * na * pi * m;
sb = -1 * nb * pi * m;
sc = -1 * nc * pi * m;
sd = -1 * nd * pi * m;
sg = -1 * ng * pi * m;
sh = -1 * nh * pi * m;

A = zeros( 2, 2, m_size );
B = zeros( 2, 2, m_size );
C = zeros( 2, 2, m_size );
% D = zeros( 2, 2, length(m) );
G = zeros( 2, 2, m_size );
% H = zeros( 2, 2, length(m) );


A( 1, 1, : ) = cos( sa );
A( 1, 2, : ) = -i * sin( sa ) / ga;
A( 2, 1, : ) = -i * ga * sin( sa );
A( 2, 2, : ) = A( 1, 1, 1:end );

B( 1, 1, : ) = cos( sb );
B( 1, 2, : ) = -i * sin( sb ) / gb;
B( 2, 1, : ) = -i * gb * sin( sb );
B( 2, 2, : ) = B( 1, 1, 1:end );

C( 1, 1, : ) = cos( sc );
C( 1, 2, : ) = -i * sin( sc ) / gc;
C( 2, 1, : ) = -i * gc * sin( sc );
C( 2, 2, : ) = C( 1, 1, 1:end );

G( 1, 1, : ) = cos( sg );
G( 1, 2, : ) = -i * sin( sg ) / gg;
G( 2, 1, : ) = -i * gg * sin( sg );
G( 2, 2, : ) = G( 1, 1, 1:end );

% sa,sb,sc,sd,sg,sh is not used from here to last, so, clear them for more memory.
clear( 'sa' );
clear( 'sb' );
clear( 'sc' );
clear( 'sd' );
clear( 'sg' );
clear( 'sh' );

%%

% Because of B==D==G ,
% M1 = (GB)^5 * (AB)^5 * (CD)^5 * (BA)^5 * (HG)^5 => M1 = G * (BG)^4 * (BA)^5 * B * (CB)^5 * (BA)^5 * (BG)^4 * B * G
% so, A and C can be clear from memory after we get BA and CB.
% We must clear all varibles not to be used again.

% Step 1. Calculate BA, clear A
BA = Mat3dx( B, A );
clear( 'A' );

% Step 2. Calculate CB, clear C
CB = Mat3dx( C, B );
clear( 'C' );

% Step 3. get BG, then calculate (BG)^4 ,clear BG
BG = Mat3dx( B, G );
BG4 = Mat3dx( BG, BG );
clear( 'BG' );
BG4 = Mat3dx( BG4, BG4 );


% Step 4. calculate (BA)^5, clear BA
BA5 = Mat3dx( BA, BA );
BA5 = Mat3dx( BA5, BA5 );
BA5 = Mat3dx( BA5, BA );
clear( 'BA' );

% Step 5. calculate (CB)^5 , clear CB
CB5 = Mat3dx( CB, CB );
CB5 = Mat3dx( CB5, CB5 );
CB5 = Mat3dx( CB5, CB );
clear( 'CB' );

%% start calculate M1
% now, M1 = G * BG4 * BA5 * B * (CB5 * BA5) * BG4 * B * G;
% we must start calculation from CB5 * BA5 or B * CB5 , because one Matrix
% must to be clear after every multiplication for more memory.
CBA5 = Mat3dx( CB5, BA5 );
clear( 'CB5' );
% now, M1 = G * BG4 * BA5 * B * (CBA5 * BG4) * B * G;
CBG4 = Mat3dx( CBA5, BG4 );
clear( 'CBA5' );
% now, M1 = G * BG4 * BA5 * B * (CBG4 * B) * G;
CB5B = Mat3dx( CBG4, B );
clear( 'CBG4' );
% now, M1 = G * BG4 * BA5 * B * (CB5B * G);
CB5G = Mat3dx( CB5B, G );
clear( 'CB5B' );
% now, M1 = G * BG4 * BA5 * (B * CB5G);
BCB5G = Mat3dx( B, CB5G );
clear( 'B' );
clear( 'CB5G' );
% now, M1 = G * BG4 * (BA5 * BCB5G);
BAG = Mat3dx( BA5, BCB5G );
clear( 'BA5' );
clear( 'BCB5G' );
% now, M1 = G * (BG4 * BAG);
BGG = Mat3dx( BG4, BAG );
clear( 'BG4' );
clear( 'BAG' );
% now, M1 = G * BGG;
M1 = Mat3dx( G, BGG );
clear( 'G' );
clear( 'BGG' );
% now, M1 done
%%
r1 = zeros( 1, m_size );
r1( 1:end ) = 2 * g0 ./ ( g0 * M1( 1, 1, : ) + M1( 1, 2, : ) * g0^2 + M1( 2, 1, : ) + M1( 2, 2, : ) * g0 );
clear( 'M1' );
R1 = r1 .* ( r1(:)' );
clear( 'r1' );

plot( m, R1, 'k' );
axis( [ 0.1, 0.9, 0, 1 ] );
ylabel( 'Transmission' );
%%
t = cputime - t0;
disp( t );
%%

程序运行出结果(画出图)所需时间92.3秒,内存从320-1220M,平均900M。总算在有生之年看到结果了,热泪盈眶。

下面,说一下编程思想。
1。首先,观察你的程序,发现用的一个超级for循环,这让我们无法在有生之年看到结论。所以,全部改成向量和矩阵运算。直接运行发现内存不够,靠,我2G内存都不够,继续优化。观察了一下,A,B,C,D,G,H,M1是内存占用大户,还有一些中间结果。
2。再看你的参数定义,发现B,D,G三个量完全一样,优化,只存1个即可,然后在运算过程中保证每次矩阵相乘都可以至少clear掉一个矩阵,这样边算边clear,直到最后。程序里做了简单注释,看看就明白了。
3。不知道自己逻辑写错没,这里不得不提一下,你的coding style实在是太糟糕了,我看了第一眼你的程序就知道可以优化,但是实在没兴趣再看第2眼,所以详细的逻辑过程我不想在去做verification了。coding style这个东西,一定要早早注意并形成好的代码风格,这个非常影响代码编写效率,易维护性和执行效率。
论坛里很多人都有着很糟糕的coding style,大家都应该注意这一点。工作中如果写出这样的代码,直接就沦为垃圾代码重写了。

remnant
2008-07-22, 14:57
这个程序在内存上还可以进一步优化,比如,先产生A,B(只产生A,B)然后计算好
M1中需要用A,B做运算的部分。然后,clear掉不需要再次用到的变量。

sa7312
2008-07-23, 08:08
remnant楼主:
  非常感谢您的鼎力帮助,我用你的方法自己优化了我的程序,运行一次耗时59秒,速度超快!您真是太伟大了!因为兴奋,昨晚我连续工作到现在!
  谢谢,非常感谢!
  我是个老来才学电脑的,本来是个电脑盲,再加上编程,头全大完了!见到您的程序,就如见到署光一番!
  我工作单位在广西宜州市,我的QQ号是771089083,QQ名“老爷子”,邮箱是[email protected]。欢迎您和家人到广西宜州市来观光旅游和指导工作!之所以写上这些,没有别的意思,也不奢望什么,只是想表示我诚挚地谢意!
  今后还恳请继续得到您的指导和帮助,再次感谢您!

                          初学者:老爷子拜谢 

remnant
2008-07-23, 08:37
好,先上程序,边看边说。
%%
clear;
clc;
%%
t0 = cputime;

e0 = 8.85 * 10^(-12);
p0 = 4 * pi * 10^(-7);
c0 = 3 * 10^8;
a = 3 * 10^(-10);

na = sqr...

晕啊,忘记把调用的一个子程序放出来了,补上,2 x 2 x length 的3d矩阵相乘的子程序。

function [ prMat ] = Mat3dx( MatA, MatB )
%% 2 x 2 x m matrix multiplier
A11xB11 = MatA( 1, 1, : ) .* MatB( 1, 1, : );
A11xB12 = MatA( 1, 1, : ) .* MatB( 1, 2, : );
A12xB21 = MatA( 1, 2, : ) .* MatB( 2, 1, : );
A12xB22 = MatA( 1, 2, : ) .* MatB( 2, 2, : );

A21xB11 = MatA( 2, 1, : ) .* MatB( 1, 1, : );
A21xB12 = MatA( 2, 1, : ) .* MatB( 1, 2, : );
A22xB21 = MatA( 2, 2, : ) .* MatB( 2, 1, : );
A22xB22 = MatA( 2, 2, : ) .* MatB( 2, 2, : );

prMat( 1, 1, : ) = A11xB11 + A12xB21;
prMat( 1, 2, : ) = A11xB12 + A12xB22;
prMat( 2, 1, : ) = A21xB11 + A22xB21;
prMat( 2, 2, : ) = A21xB12 + A22xB22;

说的那么客气,搞的我都不好意思了。
共同进步吧。学无止境。


另外,如果你老是需要做类似上面这种大数据量的处理,建议装Linux然后安装Linux版的
Matlab,执行速度会再次改善。这是由于Linux系统的内存管理机制和windows的差异造成的。
还有,如非必要,尽量不要clear掉中间产生的过度变量,那样的话一旦程序结果出错,跟踪
debug起来比较麻烦。提高程序效率的关键还是算法和coding style,要简洁高效。

未注册
2011-12-21, 16:49
另外,如果你老是需要做类似上面这种大数据量的处理,建议装Linux然后安装Linux版的
Matlab,执行速度会再次改善。这是由于Linux系统的内存管理机制和windows的差异造成的。
还有,如非必要,尽量不要clear掉中间产生的过度变量,那样的话一旦程序结果出错,跟踪
debug起来比较麻烦。提高程序效率的关键还是算法和coding style,要简洁高效。[/QUOTE]

看了您的回复,十分受用。想请教一下,如果for循环中有许多if、continue等语句,还能用矩阵运算来代替for循环吗?我有个程序,要循环几百万次十分慢,如果可以的话,我可以把程序贴上来,希望您指教,感谢!