Hilfe bei Gauß-Seidel Verfahren und bei Newtonverfahren
-
Hallo Leute,
ich bin kurz davor zum Strick zu greifen. Mein Programm des Gauß-Seidel Verfahrens (Einzelschrittverfahren) klappt nicht, ich denke der Algorithmus ist irgendwie falsch ins Programm geschrieben worden. Blicke aber überhaupt nicht mehr durch.
Dann habe ich noch das Newtonverfahren, es funktioniert ebenfalls nicht korrekt.
Beide Aufgaben bekomme ich auf dem Papier ohne Probleme hin, habe jedoch, da ich noch nicht so lange programmiere Probleme diese Programmtechnisch umzusetzen.Wäre echt nett, wenn sich jemand bereit erklären würden mir zu helfen.
Schreibt eure Email Adresse mit, dann schicke ich euch meine Quellcodes, usw.
-
Wenn der Quellcode nicht allzu lang ist, kannst du ihn doch hier posten.
Allgemein sieht das Einzelschrittverfahren doch so aus:
x\_i^{(k+1)}=- \frac 1 {a\_{ii}} \left[ \sum_{j=1}^{i-1} a_{ij} x\_j^{(k+1)} + \sum \_{j=i+1} ^ n a_{ij} x\_j^{(k)} - b\_i \right], i=1..n
Da kann man natürlich schön viele Indexfehler einbauen! Also, poste doch mal die Stellen, die nicht funktionieren, würde es mir, wenn ich Zeit habe, wohl mal ansehen...Edit:
Vielleicht kannst du dir hier ja auch ein wenig abschauen.
-
void rechn (double a[][N], double b[], double x[], double xst[])
{
int i,iter=0,isoll=0;while(isoll!=1)
{
x[0]=xst[0];
x[1]=xst[1];
x[2]=xst[2];
x[3]=xst[3];
iter=iter+1;x[0]=(b[0]-(a[0][1]*xst[1])-(a[0][2]*xst[2])-(a[0][3]*xst[3]))/a[0][0];
x[1]=(b[1]-(a[1][0]*xst[0])-(a[1][2]*xst[2])-(a[1][3]*xst[3]))/a[1][1];
x[2]=(b[2]-(a[2][0]*xst[0])-(a[2][1]*xst[1])-(a[2][3]*xst[3]))/a[2][2];
x[3]=(b[3]-(a[3][0]*xst[0])-(a[3][1]*xst[1])-(a[3][2]*xst[2]))/a[3][3];if(fabs(double((x[0]-xst[0])&&(x[1]-xst[1])&&(x[2]-xst[2])&&(x[3]-xst[3])))<=eps)/* eps ist Makro*/
isoll=1;if(iter==itermax)/*itermax ist Makro*/
{
printf("\nIterationsgrenze erreicht\n");
printf("\n eps=%.0e\n",eps);
printf("\niter=%d\n",iter);for(i=0;i<N;i++)
{
printf("\nxst[%d]=%lf\n\nx[%d]=%lf\n",i,xst[i],i,x[i]);
}
}
}
}/*Itermax wird immer überschritten*/
/*xst sind vorgegeben mit Null*/
-
void rechn (double a[][N], double b[], double x[], double xst[]) { int i,iter=0,isoll=0; while(isoll!=1) { x[0]=xst[0]; x[1]=xst[1]; x[2]=xst[2]; x[3]=xst[3]; iter=iter+1; x[0]=(b[0]-(a[0][1]*xst[1])-(a[0][2]*xst[2])-(a[0][3]*xst[3]))/a[0][0]; x[1]=(b[1]-(a[1][0]*xst[0])-(a[1][2]*xst[2])-(a[1][3]*xst[3]))/a[1][1]; x[2]=(b[2]-(a[2][0]*xst[0])-(a[2][1]*xst[1])-(a[2][3]*xst[3]))/a[2][2]; x[3]=(b[3]-(a[3][0]*xst[0])-(a[3][1]*xst[1])-(a[3][2]*xst[2]))/a[3][3]; if(fabs(double((x[0]-xst[0])&&(x[1]-xst[1])&&(x[2]-xst[2])&&(x[3]-xst[3])))<=eps)/* eps ist Makro*/ isoll=1; if(iter==itermax)/*itermax ist Makro*/ { printf("\nIterationsgrenze erreicht\n"); printf("\n eps=%.0e\n",eps); printf("\niter=%d\n",iter); for(i=0;i<N;i++) { printf("\nxst[%d]=%lf\n\nx[%d]=%lf\n",i,xst[i],i,x[i]); } } } } /*Itermax wird immer überschritten*/ /*xst sind vorgegeben mit Null*/
void rechn (double a[][N], double b[], double x[], double xst[])
Warum double a[][N]? Die Matrix A kann doch nur quadratisch sein. Außerdem funktioniert deine Version ja nur mit (4x4)-Matrizen. IMHO wäre es übersichtlicher (und man könnte es gleich füt (nxn)-Matrizen programmieren), wenn man das alles über Schleifen machen würde. Wenn ich das richtig verstanden habe, ist xst nur eine temporäre Größe, kann also in der Funktion rechn erstellt werden.
Mein Vorschlag wäre so etwas:
void rechn(double** a, double* b, unsigned int dim)
x[0]=xst[0]; //werden hier dann x[1]=xst[1]; //nicht alle x[2]=xst[2]; //x[i] auf Null x[3]=xst[3]; //gesetzt?
x[0]=(b[0]-(a[0][1]*xst[1])-(a[0][2]*xst[2])-(a[0][3]*xst[3]))/a[0][0]; x[1]=(b[1]-(a[1][0]*xst[0])-(a[1][2]*xst[2])-(a[1][3]*xst[3]))/a[1][1]; x[2]=(b[2]-(a[2][0]*xst[0])-(a[2][1]*xst[1])-(a[2][3]*xst[3]))/a[2][2]; x[3]=(b[3]-(a[3][0]*xst[0])-(a[3][1]*xst[1])-(a[3][2]*xst[2]))/a[3][3]; //x[0]=b[0]/a[0][0]; //x[1]=b[1]/a[1][1]; //...
Und dann das gleiche wieder von vorne...
Und wo geht hier das Einzelschrittverfahren ein?
Die Werte, die man gerade neu errechnet hat, sollen doch für die Berechnung der weiteren Werte benutzt werden (das ist ja gerade der Unterschied zum Gesamtschrittverfahren, wenn ich mich nicht irre...).also z.B.:
x_neu[2] = -1/a[2][2]*(a[2][1]*x_neu[1] + a[2][3]*x_alt[3] + a[2][4]*x_alt[4] - b[2]);
-
x[0]=xst[0];//Auf Null gesetzt? x[1]=xst[1];//Ja, aber nur beim ersten Mal, x[2]=xst[2];//danach wird x[i] ja wieder überschrieben x[3]=xst[3];//und zwar bei den Gleichungen
Mit deiner Frage, wo das Einzelschrittverfahren eingeht hattest du recht.
Habe es jetzt folgendermaßen geändert:void rechn (double a[][N], double b[], double x[], double xst[],double xo[]) { int i,iter=0,isoll=0; while(isoll!=1) { xo[0]=xst[0]; xo[1]=xst[1]; xo[2]=xst[2]; xo[3]=xst[3]; iter=iter+1; x[0]=(b[0]-(a[0][1]*xo[1])-(a[0][2]*xo[2])-(a[0][3]*xo[3]))/a[0][0]; x[1]=(b[1]-(a[1][0]*xo[0])-(a[1][2]*xo[2])-(a[1][3]*xo[3]))/a[1][1]; x[2]=(b[2]-(a[2][0]*xo[0])-(a[2][1]*xo[1])-(a[2][3]*xo[3]))/a[2][2]; x[3]=(b[3]-(a[3][0]*xo[0])-(a[3][1]*xo[1])-(a[3][2]*xo[2]))/a[3][3];
Immernoch die selbe Rechnung wie vorher (iterationsgrenze erreicht);
Ich habe irgendwie das Gefühl, als stimmt hier etwas nicht:
if(fabs(double((x[0]-xo[0])&&(x[1]-xo[1])&&(x[2]-xo[2])&&(x[3]-xo[3])))<=eps) isoll=1;
Was meinst du???
Das mit dem IMHO habe ich noch nicht drauf, deswegen bleibt mir leider nichts anderes übrig, als es so zu machen.
Danke noch für den Tip mit der Colorierung.
-
syoussef schrieb:
xst sind vorgegeben mit Null
x[0]=xst[0];//Ja, die x[i] werden zwar überschrieben, x[1]=xst[1];//dann aber gleich wieder auf Null gesetzt, x[2]=xst[2];//da sich die xst[i] ja in der Zwischenzeit x[3]=xst[3];//nicht geändert haben!
Wieso noch mehr temporäre Arrays? Eigentlich kannst du alle Berechnungen in dem einen x machen! Wird dadurch sogar noch einfacher! Den vorangegangenen Iterationsschritt muß man nur speichern, um eine Abbruchbedingung zu haben (|x_neu-x_alt|<eps oder so)
syoussef schrieb:
Ich habe irgendwie das Gefühl, als stimmt hier etwas nicht:
if(fabs(double((x[0]-xo[0])&&(x[1]-xo[1])&&(x[2]-xo[2])&&(x[3]-xo[3])))<=eps) isoll=1;
Ja, das habe ich übersehen.
Du könntest es so machen:
[pseudocode]
r = sqrt( sum(x_neu[i]-x_alt[i])^2, i=0..3) );
if(r < eps) fertig!
else weitermachen!
[/pseudocode]oder so:
if( fabs(x_neu[0]-x_alt[0]) < eps && fabs(x_neu[1]-x_alt[1]) < eps && fabs(x_neu[2]-x_alt[2]) < eps && fabs(x_neu[3]-x_alt[3]) < eps)
btw:
Hast du dir den Link aus meinem ersten Post mal angesehen?
-
Kanns du mir vielleicht erklären, wie ich das vorangegangene Ergebnis speichere???
Oder ist es vielleicht zu kompliziert???
Der Link, ich habe ehrlich gesagt nicht so ganz durchgeblickt.
-
Ich würde es ungefähr so machen:
[pseudocode]
do { x_alt = x_neu; //alten Vektor zwischenspeichern: //for(int i = 0; i < n; ++i) // x_alt[i] = x_neu[i]; //wenn du dich also auf 4-D beschränken willst: n = 4 berechne x_neu wie oben berechne r = Differenz zwischen x_neu und x_alt //Residuum berechnen: //r=0; //for(int i = 0; i < n; ++i) // r += (x_neu-x_alt)^2; } while(sqrt(r) < eps)
[/pseudocode]
Nur mal so aus Interesse: Wofür brauchst du das ganze? Schule/Uni? Welche Vorkenntnisse in Numerik/Programmieren?
-
Für die Uni.
Hatte letztes Semester C-Grundlagenkurs
(der Prof. war die Hälfte der Zeit krank)
jetzt ein Semester Numerik.
Das Problem ist nur es sind zwei verschiedene Programmiersprachen im Fach Numerik (VBA und C)
und der Prof präsentiert die Vorlesung in VBA (Beispiele, etc.)
Auf dem Papier kriege ich die Aufgaben ja hin, es hängt halt nur etwas am Programmtechnischen.