Dauerschleife/While < C/C++ < Programmiersprachen < Praxis < Informatik < Vorhilfe
|
Aufgabe | Gegeben ist eine monoton wachsende Funktion f(x) in einem Intervall [a,b] mit f(a) < 0 und f(b) > 0.
Die Nullstelle im Intervall [a,b] lässt sich durch Intervallschachtelung nach folgendem Algorithmus
bestimmen:
1. Berechne den Intervallmittelpunkt m := (a + b) / 2.
2. Falls f(m) > 0, dann betrachte [a,m] (die untere Hälfte des betrachteten Intervalls) als das
nächste zu bearbeitende Intervall, andernfalls das Intervall [m,b] (die obere Hälfte des betrachteten
Intervalls).
3. Wiederhole die Schritte 1. und 2. solange, bis |f(m)| genügend klein ist, d.h. kleiner als eine
vorgegebene Konstante Epsilon (0.01) ist. |
Mein Problem liegt in der while-Schleife, die mir immer nur 4 bestimmte Werte liefert und das dauerhaft.
Ich poste zum Verständnis einfach mal den ganzen Code, vielleicht kann mir ja jemand weiter helfen.
Ich sitze nämlich fest.
Danke im Voraus.
#include <stdio.h>
#define Epsilon 0.01
float nullstelle(float k, float l)
{
float p;
p = (k+l)/2;
return p;
}
float funktion(float x)
{
float y;
y = (x*x) - 5;
return y;
}
float main (void)
{
float m, a, b, Erg;
printf("Bitte Werte fuer a und b eingeben.");
scanf("%f %f", &a, &b);
m = nullstelle(a,b);
printf("Mittelwert: [mm] %f\n", [/mm] m);
Erg = funktion(m);
if(funktion(m)>0)
{
m = nullstelle(a,m);
}
else
{if(funktion(m)<0)
{
m = nullstelle(m,b);
}
}
printf("Mittelwert nach Funktionswertuebergabe = % f", m);
if(Erg<0)
{
Erg = Erg*(-1);
}
while(Erg>=Epsilon)
{
Erg = funktion(m);
if(Erg<0)
{
Erg = Erg*(-1);
}
if(funktion(m)>0)
{
m = nullstelle(a,m);
}
else
{if(funktion(m)<0)
{
m = nullstelle(m,b);
}
}
printf("Ergebniswert: %f", Erg);
}
}
|
|
|
|
Hallo!
zunächst ist ein #define etwas, das man sehr sehr häufig verwendet. Aber es können auch unerwartete Effekte entstehen. wenn du z.B. folgendes verwendest:
printf(" Epsilon wurde unterschritten, Schleife bricht jetzt ab.")
erhälst du als Ausgabe:
"0.01 wurde unterschritten, Schleife bricht jetzt ab."
denn das #define ersetzt JEDES Vorkommen des Worts Epsilon.
besser:
const float Epsilon = 0.01;
Nun zu deinem Code:
Erg = funktion(m);
if(funktion(m)>0)
Warum nutzt du nicht einfach Erg? Jedes mal, wenn du funktion(m) aufrufst, wird diese Funktion erneut ausgeführt. Es macht also Sinn, den Wert einmal in Erg zu speichern, und dann nur noch diese Variable zu verwenden.
1: |
| 2: | if(funktion(m)>0)
| 3: | {
| 4: | m = nullstelle(a,m);
| 5: | }
| 6: | else
| 7: | {if(funktion(m)<0)
| 8: | {
| 9: | m = nullstelle(m,b);
| 10: | }
| 11: | }
|
OK, m ist der Wert zwischen a und b. Wenn du m = nullstelle(m,b); schreibst, was machtg dein Code dann mit dem neuen Wert von m? Nichts mehr!
Im Prinzip ist es doch so: Wenn m>0 ist, dann soll m der neue Wert von b werden, sonst der neue Wert von a. Also eher a = nullstelle(m,b)
Dann versuchst du da was mit nem Vorzeichen... Schreib doch lieber while(Erg> -Epsilon && Erg < Epslion)
Und generell ist mir nicht klar, was du mit dem Code vor der while-Schleife machen möchtest. Im Prinzip reicht doch das, was in der while-Schleife steht.
|
|
|
|
|
Ich habe meinen Code jetzt verbessert, erhalte allerdings immer noch eine Dauerschleife:
#include <stdio.h>
float nullstelle(float k, float l)
{
float p;
p = (k+l)/2;
return p;
}
float funktion(float x)
{
float y;
y = (x*x) - 5;
return y;
}
float main (void)
{
const float Epsilon = 0.01;
float m, a, b, Erg;
printf("Bitte Werte fuer a und b [mm] eingeben.\n");
[/mm]
scanf("%f %f", &a, &b);
m = nullstelle(a,b);
Erg = funktion(m);
while(Erg> Epsilon || Erg < 0)
{
m = nullstelle(a,b);
Erg = funktion(m);
if(Erg>0)
{
b = nullstelle(a,m);
}
else
{
if(Erg<0)
{
a = nullstelle(m,b);
}
}
printf("Ergebniswert: %f", Erg);
}
}
|
|
|
|
|
Hallo!
So sieht das schon besser aus.
Wie du in deinem anderen Beitrag schreibst, hatte ich nen Fehler bei der while-Schleife. Aber du meinst nun sicher auch eher
while(Erg> Epsilon || Erg < -Epsilon)
Nun zu deinem Code:
1: |
| 2: | while(Erg> Epsilon || Erg < 0)
| 3: | {
| 4: | m = nullstelle(a,b);
| 5: | Erg = funktion(m);
| 6: |
| 7: | if(Erg>0)
| 8: | {
| 9: | b = nullstelle(a,m);
| 10: | }
| 11: | else
| 12: | {
| 13: | if(Erg<0)
| 14: | {
| 15: | a = nullstelle(m,b);
| 16: | }
| 17: | }
| 18: | ...
|
In Zeile 4 berechnest du den neuen Mittelpunkt.
Liegt der Funktionswert über 0, berechnest du nochmal einen neuen Mittelpunkt, und zwar zwischen a und dem bereits berechneten Mittelpunkt. Das heißt, das neue Intervall entspricht dem unteren Viertel des alten. Zugegeben, ich habe das eben auch nicht gesehen.
Jedenfalls ist es nun möglich, daß du mit dem oberen Wert bereits unter die Nullstelle rutschst, und so die Nullstelle gar nicht mehr im Intervall liegt. Das gibt ne Endlosschleife. Es muß heißen:
1: |
| 2: |
| 3: | if(Erg>0)
| 4: | {
| 5: | b = m;
| 6: | } |
Ansonsten kannst du ggf. auch noch eine printf-Anweisung in die While-Schleife einbauen, um dir nach jedem Durchlauf a, b und m auszugeben. Daran kannst du auch ablesen, ob es funktioniert.
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 12:17 Fr 14.11.2014 | Autor: | Haloelite |
Danke für die nette Hilfe von allen.
jetzt wird der Funktionswert auch kleiner als Epsilon. :)
|
|
|
|
|
Hallo,
Ich verstehe nicht, was du mit
while(Erg> -Epsilon && Erg < Epslion) meinst.
Die Schleife soll doch wiederholt werden, wenn Erg eben nicht den Wert >Epsilon hat, damit es kleiner wird.
Mit while(Erg> -Epsilon && Erg < Epslion) geht man doch davon aus, dass der
Wert schon zwischen -Epsilon und Epsilon liegt?
|
|
|
|
|
hallo!
Da hast du natürlich recht!
|
|
|
|
|
Aber dennoch funktioniert mein Programm nicht und spuckt mir falsche Ergebnisse aus. :/
Weiß jemand, warum? ich habe über legt, komme aber nicht drauf.
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 20:43 Do 13.11.2014 | Autor: | chrisno |
Ich kenne mich mit der Sprache nicht so gut aus. Macht es kein Problem, dass in der Funktion kein Dezimalpunkt hinter der 5 ist?
|
|
|
|
|
Status: |
(Antwort) fertig | Datum: | 21:08 Do 13.11.2014 | Autor: | chrisno |
Ich denke, Du solltest den von Event_Horizon vorgezeichneten Weg weiter gehen.
Dass Du bei der Eingabe nicht abprüfst, ob f(a) < 0 und f(b) > 0 wird Dir hier erstmal keine Probleme machen. Früher oder später wird sich so etwas sicher rächen.
Vor der Schleife
m = Nullstelle(a;b)
Erg = f(m)
Nun aber zur Schleife:
Solange abs(Erg) > Eps
Wenn Erg) > 0, dann a = m
sonst b = m
(Das setzt voraus, dass f auf dem Intervall monoton steigt. Damit schließt Du die Hälfte der Nullstellen von vornherein aus. Das lässt sich aber in einer späteren Version noch in Ordnung bringen.)
Nun m = Nullstelle(a;b)
dann Erg = f(m)
Schleifenende
|
|
|
|
|
Hallo,
danke für den Hinweis.
Das mit dem abs(Erg) habe ich auch schon probiert, da hat er nicht reagiert.
Aber wieso ist deine Bedingung in der While-Schleife denn
"while(abs(Erg) > Eps)"?
Natürlich, das mit <Epsilon ergibt Sinn.
Aber so werden doch Werte < 0 vernachlässigt, weshalb die Schleife abbrechen würde?
|
|
|
|
|
Hi!
abs() oder fabs() sind Funktionen, die dir den Betrag einer Zahl liefern. Dummerweise funktionieren sie in C nur für ganze Zahlen (integer).
Stattdessen kannst du fabs() verwenden, musst dann aber #include <math.h> einfügen.
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 10:41 Mo 17.11.2014 | Autor: | Haloelite |
Gut, danke. =)
|
|
|
|