Verfasst am: 30.11.2011, 15:31
Titel: Hängenbleiben in der for-Schleife
Hallo allerseits,
Ich habe ein ein etwas seltsames Problem, für das mir jede Erklärung fehlt. Das folgende Programm braucht wenige Sekunden um die gewünschte Konvergenzordnung eoc für ein gegebenes m (hier: m = 3) zu berechnen.
Nun möchte ich allerdings mit einer for-Schleife nacheinander die Konvergenzordnungen für m = 1, 2, ..., 6 berechnen. Obwohl für jedes fest vorgegebene m (d.h. ohne Schleife über m) die Rechenzeit jeweils nur wenige Sekunden beträgt, bleibt das Programm bei Verwendung einer for-Schleife bereits bei m = 2 stecken und nachdem 15 min lang nichts passiert ist, habe ich dann abgebrochen.
Wie kann sowas überhaupt möglich sein und was kann man dagegen tun?
Hier mein Programm:
Code:
function konvergenzordnung
t0 = 0;
y0 = 1;
tend = 1;
dt = 1/8;
n = 9;
m = 3
for k = 1:n
v = (tend - t0)/dt;
for i = 0:(m-1)
sol(i+1,1) = t0 + i*dt;
sol(i+1,2) = exp(sol(i+1,1));
end for i = 0:(v-m)
sol = bdf(i,m,dt,sol,t0);
end
err(k) = sol(length(sol(:,1)),2) - exp(tend);
dt = dt/2;
clear sol;
end
for k = 1:(n-1)
eoc(k) = log(abs(err(k)/err(k+1)))/log(2);
end
function sol = bdf(i,m,dt,sol,t0)
sol(i+m+1,1) = t0 + (i+m)*dt;
y = 0;
for j = 0:(m-1)
y = y + alpha(m,j) * sol(i+j+1,2);
end
sol(i+m+1,2) = y/(dt-alpha(m,m));
end
Das Programm arbeitet an sich schon so wie es soll. Der von dir bemerkte Fall, dass v - m < 0 kann mit der gewählten Anfangsschrittweite von dt = 1/8 niemals auftreten, da für diese Schrittweite v = 8 und somit für alle m = 1, ..., 6 gilt, dass v - m > 1.
Da dt in jedem weiteren Schritt in der Schleife über k halbiert wird, verdoppelt sich v in jedem Schritt, die Grenzen sind also alle ok.
Das Programm arbeitet wie gesagt ja auch genau so, wie es soll, ich habe nur Probleme bei der Laufzeit der for-Schleife über m. Damit das noch klarer wird, schreibe ich hier nochmal die abgeänderte Version auf, in der das fest vorgegebene m durch die Schleife ersetzt wird:
Code:
function konvergenzordnung
t0 = 0;
y0 = 1;
tend = 1;
dt = 1/8;
n = 9;
for m =1:6 for k = 1:n
v = (tend - t0)/dt;
for i = 0:(m-1)
sol(i+1,1) = t0 + i*dt;
sol(i+1,2) = exp(sol(i+1,1));
end for i = 0:(v-m)
sol = bdf(i,m,dt,sol,t0);
end
err(k) = sol(length(sol(:,1)),2) - exp(tend);
dt = dt/2;
clear sol;
end for k = 1:(n-1)
eoc(k) = log(abs(err(k)/err(k+1)))/log(2);
end
function sol = bdf(i,m,dt,sol,t0)
sol(i+m+1,1) = t0 + (i+m)*dt;
y = 0;
for j = 0:(m-1)
y = y + alpha(m,j) * sol(i+j+1,2);
end
sol(i+m+1,2) = y/(dt-alpha(m,m));
end
naja wenns ne laufzeit frage is solltest du mal speicher allokalisieren. du erstellest bei dir ja alle matritzen dynamisch. das macht sowas sehr langsam
wie Winkow schon sagte: Matrizen dynamisch vorbelegen.
Im MATLAB Editor wirst du durch orange unterlegte Stellen auf mögliche Verbesserungen im Code hingewiesen. sol, err und eoc sollten also vorbelegt werden.
Auch wenn ich nicht weiß, was "Speicher allokalisieren" bedeutet, glaube ich doch zu wissen, was ihr meint. Und ihr habt natürlich recht, dass speziell die alphas immer wieder neu berechnet werden, was absolut nicht notwendig ist.
Daher habe ich mein Programm nun dahingehend verändert, dass die Koeffizientenmatrix A mit den alphas nun vorab generiert wird und dann in bdf nur noch auf die fertig generierten Koeffizienten zugegriffen wird.
Auch err und eoc habe ich vorab als Null-Vektoren entsprechender Größe initialisiert.
Dies (vor allem die Einführung von A) hat die Laufzeit etwa um den Faktor 10 verkürzt, danke schonmal dafür.
Dennoch bleibt mein ursprüngliches Problem bestehen. Da noch niemand Bezug auf meine ursprüngliche Frage genommen hat, versuche ichs nochmal anders zu erklären:
Die Laufzeit L einer for-Schleife F der folgenden Form (Z bezeichnet beliebige von m abhängige Anweisungen)
sollte sich doch naheliegender Weise als L(F) = L(Z(1)) + L(Z(2)) + ... + L(Z(6)) ergeben.
Mit der Einführung der Koeffizientenmatrix A für die alphas liegt die Laufzeit von Z für ein beliebiges m nun unter einer Sekunde, d.h. L(Z(m)) < 1s für alle m = 1, ..., 6. ABER: Die gesamte Schleife bleibt stecken!
Hier nochmal die aktualisierte Programmversion:
Code:
function konvergenzordnung
t0 = 0;
y0 = 1;
tend = 1;
dt = 1/8;
n = 9;
mmax = 6;
for m = 1:mmax
m
for k = 1:n
v = (tend - t0)/dt;
for i = 0:(m-1)
sol(i+1,1) = t0 + i*dt;
sol(i+1,2) = exp(sol(i+1,1));
end for i = 0:(v-m)
sol = bdf(i,m,dt,sol,t0);
end
err(k) = sol(length(sol(:,1)),2) - exp(tend);
dt = dt/2;
clear sol;
end for k = 1:(n-1)
eoc(k) = log(abs(err(k)/err(k+1)))/log(2);
end
eoc
end end
function a = alpha(m,j)
a = 0;
for k = max(m-j,1):m
a = a + binom(k,m-j)/k;
end
a = (-1)^(m-j) * a;
end
function sol = bdf(i,m,dt,sol,t0) global A;
sol(i+m+1,1) = t0 + (i+m)*dt;
y = 0;
for j = 0:(m-1)
y = y + A(m,j+1) * sol(i+j+1,2);
end
sol(i+m+1,2) = y/(dt-A(m,m+1));
end
ARG, ich bin so dämlich!
Natürlich muss das dt nach jedem Schleifendurchlauf wieder auf 1/8 zurückgesetzt werden.
Hat sich dann erledigt, aber danke trotzdem nochmals für die generellen Verbesserungsvorschläge zur Laufzeit!
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.