Programmierung einer do-while Schleife in C

Moin,
danke, hab das jetzt mal versucht umzusetzen, scheitere aber an der Fallunterscheidung. Wie muss ich die programmieren?
Und wie ist das mit der Genauigkeit? Welcher Wert bietet sich da an? Habe jetzt 0.005 gewählt. Ich muss bis auf zwei Kommastellen genau berechnen.

Vll kannst du mal eben nen Blick auf den Code werfen:

Code:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>


void main (void)
{                                       
    float rn, n, r, p, a0, b0, c0, f(a0), f(b0), f(c0);
    int i;
    i = 1.0;

    printf ("\n\t Z i n s s a t z\n");
    printf ("\t _______________\n\n\n\n");
    printf ("\t Geben Sie bitte folgende Variablen an:\n\n\n");
    printf ("\t Rentenendwert in Euro: \t"); scanf ("%f", &rn);
    printf ("\t Rate in Euro: \t\t\t"); scanf ("%f", &r);
    printf ("\t Laufzeit in Jahren: \t\t"); scanf ("%f", &n);

	a0 = 0;
	b0 = pow ( rn / (r * n),1 / n);
	b0 = (b0 * 2) - 1;
	f(a0) = r * (pow (a0,n) - 1) - rn;
	f(b0) = r * (pow (b0,n) - 1) - rn;
	c0 = ((a0 * f(b0) - b0 * f(a0)) / (f(b0) - f(a0));
	f(c0) = r * (pow (c0,n) - 1) - rn;

	while ( f(c0) > 0.005 )  {
			
			// Ermittle a und b durch Ersetzen mit c (Fallunterscheidung notwendig)
			
			c0 = ((a0 * f(b0) - b0 * f(a0)) / (f(b0) - f(a0));
			f(c0) = r * (pow (c0,n) - 1) - rn;
	}


    p = (c0 - 1.0) * 100.0;

    printf ("\n\n\t Iterationsschritte: \t\t\t%d", i);
    printf ("\n\t Der Zinssatz betraegt: \t"); printf ("%10.2f", p); printf (" Prozent\n\n\n");
}
 
Einen wunderschönen guten Tag,

Insgesamt sieht das schon ganz gut aus. Allerdings noch ein paar Anmerkungen.

C:
    float rn, n, r, p, a0, b0, c0, f(a0), f(b0), f(c0);

Du wirst in der Art die Variablen für die Funktionswerte nicht deklararieren können ( f(a0), f(b0), f(c0)). Sinnvoller ist es treffende Namen zu vergeben. Dies trifft auch auf die Argumente a0, b0. und c0 zu, z.B.

C:
float rn, n, r, p;                       // Hier vielleicht auch noch treffende Namen ausdenken
float argumentA, valueA;
float argumentB, valueB;
float argumentC, valueC;

Dadurch ist eventuell deine Funktion verständlicher.

C:
int i;
i = 1.0;

Wieso weist du der Interger-Variable i den reellen Wert 1.0 zu.

C:
int i;

i = 1;

So sieht das besser aus.

C:
a0 = 0;
b0 = pow ( rn / (r * n),1 / n); // Diese und nächste Zeile versteh ich nicht, wie kommst du auf die Gleichung?
b0 = (b0 * 2) - 1;
f(a0) = r * (pow (a0,n) - 1) - rn; // Hier muss deine Rentenformel angewendet werden
f(b0) = r * (pow (b0,n) - 1) - rn; // Hier muss deine Rentenformel angewendet werden
c0 = ((a0 * f(b0) - b0 * f(a0)) / (f(b0) - f(a0));
f(c0) = r * (pow (c0,n) - 1) - rn; // Hier muss deine Rentenformel angewendet werden
while ( f(c0) > 0.005 )  {
			
    // Ermittle a und b durch Ersetzen mit c (Fallunterscheidung notwendig)
			
    c0 = ((a0 * f(b0) - b0 * f(a0)) / (f(b0) - f(a0));
    f(c0) = r * (pow (c0,n) - 1) - rn; // Hier muss deine Rentenformel angewendet werden
}

Moin,
danke, hab das jetzt mal versucht umzusetzen, scheitere aber an der Fallunterscheidung. Wie muss ich die programmieren?

Fallunterscheidungen werden mit einer if-then-else-Abfrage behandelt. In deinem Fall muss du überprüfen, ob der Funktionswert des neu erzeugten Punktes (f( c ) bzw. valueC) größer als 0 ist oder kleiner als 0. Du ersetzt den Punkt (A oder B), der das gleiche Vorzeichen hat. Das schaffst du am besten, indem du die Quotienten (valueA / valueC) und (valueB / valueC) bildest. Ist der Quotient größer als 0, dann haben beide Funktionswerte das gleiche Vorzeichen:

C:
if(valueA / valueC > 0) {
    argumentA = arguementC;
    valueA = valueC;
}
if(valueB / valueC > 0) {
    argumentB = arguementC;
    valueB = valueC;
}

Und wie ist das mit der Genauigkeit? Welcher Wert bietet sich da an? Habe jetzt 0.005 gewählt. Ich muss bis auf zwei Kommastellen genau berechnen.

Das mit der Genauigkeit hast du schon richtig verstanden. Wenn die Abweichung von deinen Zielwert eine gewisse Grenze unterschreitet, dann kann die Schleife abgebrochen werden. In deinem Fall sollen die beiden ersten Nachkommastellen genau sein. Das heißt es muss die zweite Nachkommestelle kleiner als 0,01 sein.

Gruss
Mizi
 
Zuletzt bearbeitet:
Nabend, nochmals vielen Dank für deine Hilfe.

Habe jetzt gerade mal alles nach deinen Tipps geändert. Nur die Variaben rn etc. hab ich so gelassen,weil auch im Rest des Programms damit gearbeitet wurde. Aber das ist bei meinem Problem ja vorerst egal. Das Programm lässt sich jetzt soweit ohne Fehler kompilieren, gibt mir allerdings falsche Werte aus oder rechnet sich zu Tode. Die Genauigkeit habe ich auf 0.5 geändert, da davon mal die Rede in der Vorlesung war, meine ich.

Ich denke das Problem liegt nun noch an der Formel für die Berechnung des zweiten Startwertes. Diese hatte ich aus Quellen im Internet selbst entwickelt, vermutlich falsch. Habe sie deswegen erstmal entfernt.

So schauts nun aus:

Code:
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>


void main (void)
{                                       
    float rn, n, r, p;
    float argumentA, valueA;
    float argumentB, valueB;
    float argumentC, valueC;
    int i;
    i = 1;

    printf ("\n\t Z i n s s a t z\n");
    printf ("\t _______________\n\n\n\n");
    printf ("\t Geben Sie bitte folgende Variablen an:\n\n\n");
    printf ("\t Rentenendwert in Euro: \t"); scanf ("%f", &rn);
    printf ("\t Rate in Euro: \t\t\t"); scanf ("%f", &r);
    printf ("\t Laufzeit in Jahren: \t\t"); scanf ("%f", &n);

	argumentA = 0;
	argumentB = //Zweiter Startwert
	valueA = r * (pow (argumentA,n) - 1) - rn;
	valueB = r * (pow (argumentB,n) - 1) - rn;
	argumentC = (argumentA * valueB - argumentB * valueA) / (valueB - valueA);
	valueC = r * (pow (argumentC,n) - 1) - rn;

	while ( valueC >= 0.5 )
	{
			if(valueA / valueC > 0)
			{
    				argumentA = argumentC;
    				valueA = valueC;
			}

			if(valueB / valueC > 0) 
			{
    				argumentB = argumentC;
    				valueB = valueC;
			}
	
			argumentC = (argumentA * valueB - argumentB * valueA) / (valueB - valueA);
			valueC = r * (pow (argumentC,n) - 1) - rn;
	}


    p = (valueC - 1.0) * 100.0;

    printf ("\n\n\t Iterationsschritte: \t\t\t%d", i);
    printf ("\n\t Der Zinssatz betraegt: \t"); printf ("%10.2f", p); printf (" Prozent\n\n\n");
}


Du hattest oben ja bereits eine Formel zur Berechnung von argumentB geliefert, die jedoch problematisch ist. Inwiefern zeigt isch das bzw. wie lange ist diese gültig? Danach richtet sich ja, ob ich sie überhaupt gebrauchen kann oder nicht.

Ansonsten hatte ich zur Startwertberechnung noch eine interessante Quelle (FH Würzburg) gefunden, bin mir jedoch nicht sicher, ob das was taugt und wenn ja, wie ich das umsetzen kann.
http://www.fh-wuerzburg.de/fh/fb/all/personal/interper/GNUSCHKE/wima/kapitl09.pdf

Das ist dann dort die Seite 6 in der Tabelle. Die müsste man doch nutzen können?!

Vielen, Vielen Dank.
 
Einen wunderschönen guten Morgen,

die von dir verlinkte .pdf-Datei gibt ja bestens Auskunft genau über das Problem.

Die von mir vorgeschlagene Formel zur Berechnung der zweiten Stützstelle ist dahingehend problematisch, da diese mit der Rentenformel einen Schnittstelle hat. Diese Schnittstelle ist bei 2. Demnach darf der Aufzinsungsfaktor q nur Werte zwischen 0 und 2 annehmen, außer dem Wert 1, da hier eine Polstelle besteht (Division durch 0).

In der .pdf-Datei steht allerdings, dass Aufzinsungsfaktoren gewöhnlich Werte zwischen 1,01 und 1,09 annehmen. Das macht das ganze dahingehend angenehmer, dass der Suchraum erheblich verringert wird und somit auch die Polstelle eleminiert ist. Wenn das deine Aufgabenstellung zulässt, gebe ich dir folgende Empfehlung für die Startwerte (entsprechend der .pdf-Datei):

C:
argumentA = 1.01
argumentB = 1.09

Jetzt müssen wir uns nur noch im klaren werden, wie die Genauigkeit aussehen mag. Da hilft wieder ein Blick in die .pdf-Datei. Dort steht, dass der Zinssatz gewöhnlich auf zwei Nachkommastellen genau angegeben wird. Was wiederum bedeutet, dass der Aufzinsungsfaktor für vier Nachkommastellen genau angegeben werden muss. Wenn dies in deiner Aufgabenstellung genauso verlangt wird, bedeutet das für dich, dass dein Abbruchkriterium für den Aufzinsungsfaktor q wie folgt lautet:

f( q ) < 0.0001

Dass du nicht die richtigen Nullstellen findest, ist mir klar. Du verwendest zur Berechnung der Funktionswerte immer noch nicht die Rentenformel. Das ist aber für das iterative Nullstellenverfahren Regula Falsi notwendig. Dort werden zunächst zwei Stellen geraten und die Funktionswerte dazu berechnet. Somit hast du nun zwei Punkte deiner Funktion zwischen denen eine Nullstelle ist (entsprechend geschicktes Raten vorausgesetzt). Diese wird annäherungsweise mittels einer Geraden zwischen diesen beiden Punkten bestimmt. Du erhälst näherungsweise eine Nullstelle. Zu dieser errechnest du dir wieder den Funktionswert und somit hast du einen neuen Punkt auf der Funktion. Der Punkt, dessen Funktionswert das gleiche Vorzeichen hat, wird ersetzt. Du bildest wieder eine Gerade zwischen deinen Punkten und erhälst wieder annäherungsweise eine Nullstelle. Das machst du dann solange bis dir die Nullstelle genau genug ist. In Wikipedia wird dies schön an einer Sinusfunkton aufgezeigt.

Gruss
Mizi
 
Zuletzt bearbeitet:
Das Problem ist, dass unser Dozent verlangt, dass wir Ausnahmefälle abfangen. Ein Bsp ist eine R = 60, Rn= 10000, n = 2. P ist dann ungefähr 16000 %. Deshalb kann ich nicht einfach einen Startwert von q=1.09 setzen.

Naja, vielen Dank nochmal für die Hilfe, aber das nützt wohl nichts mehr, das Ganze muss morgen früh abgegeben werden.....

Gruß
 
Zurück