# Programmierung einer do-while Schleife in C



## TRANSformator (15. Dezember 2008)

Hallo,
ich habe ein Programm in C geschrieben, was mit Hilfe von regula falsi den Zinsatz in der Rentenformel berechnet. Das funktioniert auch soweit, allerdings sollen auch die Iterationsschritte ausgegeben werden. Dabei ahbe ich den Zähler aber irgendwie falsch gesetzt.
Jetzt sagte man mir auch, dass ich aus meiner for Schleife erst noch eine do-while Schleife machen soll.

da meine Programmierkenntnisse nicht so berauschend sind, scheiter ich schon an der Änderung von for-Schleife zu do-while.

Kann sich mal jemand meinen Code anschauen und mir erklären, wie ich daraus eine do-while Schleife mache und wo ich da den Zähler für die Iterationsschritte setzen muss? 


```
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>


void main (void)
{										
	float rn, n, r, q, q1, p;
	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);


	for (q = 1.001; q < 1000000; q += 0.001)
	{
		if ((pow(q,n) - ((rn / r) * q) + (rn / r - 1)) > 0)
		break;
	}	
	
	do
	{
		q1 = ((((n - 1.0) * pow(q,n)) + 1.0) - rn / r) / ((n * pow(q,n - 1.0)) - (rn / r));	
	}
	
	while (fabs(q1 - q) > 0.1);
	i++;

	p = (q1-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");
}
```


Wäre super, wenn mir da jemand helfen könnte.
Danke


----------



## Mr Apfelkuchen (15. Dezember 2008)

Also erstmal würde ich dir empfehlen die Variabeln nicht nur mit einem Buchstaben zu deklarieren , um es übersichtlicher zu machen.Dann zum Code... 


> for (q = 1.001; q < 1000000; q += 0.001)
> {
> if ((pow(q,n) - ((rn / r) * q) + (rn / r - 1)) > 0)
> break;
> }


Diese Schleife wird genau 999.999.999 mal durchlaufen... ich glaube das dürfte um die 10 Minuten dauern (zumindestens auf meinm Rechner)
Da ich die Aufgabe des Programms nicht ganz durchschaue würde ich dich bitten einmal zu beschreiben was das Programm genau tun soll


----------



## TRANSformator (15. Dezember 2008)

Moin,
danke erstmal für deine Antwort.
Das Programm ist genau genommen nur ein Ausschnitt aus einem größeren Programm, einem Zins-und Rentenrechner. Der Rest vom Programm ist jedoch fertig und ich habe ihn der Übersichtlichkeit wegen weggelassen.

Dieser Programmausschnitt berechnet nun anhand der Rentenformel die Variable Zinssatz q. Dabei muss der Benutzer vorher die Variablen Rentenendwert Rn, Laufzeit n und die Rate r angeben. Dies ist nicht so einfach, weil man die Formel nicht anch q umstellen kann. Die Berechnung ist aber über ein Näherungsverfahren, z.B. regula falsi oder Newton-Algorithmus möglich. Die Berechnung funktioniert mittlerweile auch, allerdings macht das Programm dabei zuviele Iterationsschritte. Das könnte an der 1 000 000 liegen. Wie könnte ich das denn ändern?
 Ich bin selbst absoluter Laie und hätte vor einer Woche auch nie gedahct, dass ich mal sowas programmiere .....


----------



## deepthroat (16. Dezember 2008)

Hi.





TRANSformator hat gesagt.:


> ich habe ein Programm in C geschrieben, was mit Hilfe von regula falsi den Zinsatz in der Rentenformel berechnet. Das funktioniert auch soweit, allerdings sollen auch die Iterationsschritte ausgegeben werden. Dabei ahbe ich den Zähler aber irgendwie falsch gesetzt.


Ja, du erhöhst den Zähler nur einmal nachdem alle Iterationen bereits beendet sind. Um die Iterationen zu zählen müßtest du den Zähler in den Schleifen inkrementieren.


TRANSformator hat gesagt.:


> Jetzt sagte man mir auch, dass ich aus meiner for Schleife erst noch eine do-while Schleife machen soll.


Wozu soll das gut sein? Man kann jede Schleife durch eine andere Form einer Schleife ersetzen, aber das allein macht noch keinen Sinn.

Die do-while-Schleife die du dort programmiert hast, macht auch wenig Sinn: entweder wird sie genau einmal durchlaufen, oder es ist eine unendliche Schleife, denn die Abbruchbedingung ändert sich ja nicht...

Schreib doch mal genau welche Formel du da berechnest.

Gruß

PS: Der Rückgabetyp der Funktion main muss int sein!


----------



## TRANSformator (16. Dezember 2008)

Hallo,
die Berechnung wird nach der Rentenformel durchgeführt:

Rn = r * ((q^n - 1) / (q - 1))

Ich möchte jetzt q ausrechnen. Dies ist nur über ein Näherungsverfahren möglich. ich soll regula falsi benutzen.

Also:  f(q)=r* ((q^n-1) / (q-1)) -Rn


Zu den Schleifen:
Mein Dozent meinte nur beiläufig kurz, ich solle aus der for-Schleife eine Do-While machen. Wie er das gemeint hat, weiß ich nicht.

Nu hab ich hier den Code einmal mit der For-Schleife (wie oben) und dann noch nur mit while-Schleife und einmal mit do-While. Aber ändern tut das nichts. Habe jetzt den Zähler mal in die erste Schleife gesetzt.


```
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>


void main (void)
{                                       
    float rn, n, r, q, q1, p;
    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);


{
	q = 1.001;
	while(q < 1000000)

	{
		if ((pow(q,n) - ((rn / r) * q) + (rn / r - 1)) > 0)
		break;
		q += 0.001;
	}
}
 
    do
    {
        q1 = ((((n - 1.0) * pow(q,n)) + 1.0) - rn / r) / ((n * pow(q,n - 1.0)) - (rn / r));   
    }
   
    while (fabs(q1 - q) > 0.1);

    p = (q1-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");
}
```



```
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <ctype.h>


void main (void)
{										
	float rn, n, r, q, q1, p;
	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);


{
	q = 1.001;
	do
	{
		if ((pow(q,n) - ((rn / r) * q) + (rn / r - 1)) > 0)
		break;
		q += 0.001;
		i++;
	}
		
	while(q < 1000000);
}
	
	do
	{
		q1 = ((((n - 1.0) * pow(q,n)) + 1.0) - rn / r) / ((n * pow(q,n - 1.0)) - (rn / r));
	}
	
	while (fabs(q1 - q) > 0.1);
	

	p = (q1-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");
}
```

Ich muss halt möglichst wenig Iterationsschritte machen, da das laut Dozent die Qualität des Programms ausmacht. Meines macht bei den meisten Rechnungen noch zuviele. Ich weiß leider nicht, wie ich das optimieren soll, da ich jetzt schon heillos überfordert bin. Ich studiere einen Wiso-Studiengang im ersten Semester, bei dem der Mathematik-Hauptkurs bisher gut zu schaffen ist. Wir sollen auch die Grundkenntnisse im Programmieren lernen, die fehlen uns aber bisher, weil wir wirklich nur die einfachsten Sachen gelernt haben. Wir arbeiten nichtmal mit Zeigern. Jetzt sollen wir aber ein Programm schreiben, bei dem der Großteil des Programms leicht zu programmieren ist, für den es aber keine Punkte gibt. Beurteilt wird eigentlich nur die Berechnung von q. Programmierkenntnisse sind dafür auch nur zweitrangig. Das schwierige daran ist die Mathematik, die komplizierter als im Hauptkurs ist. Das soll mal einer verstehen. 

Der Rest vom Programm läuft halt, dort müssen ja nur Formeln umgestellt werden, q berechnet er mir ja auch, nur halt mit zuvielen Iterationsschritten. ich hab keine Ahnung, wie ich die das vereinfachen kann.

Ps: Was meinst du mit Rückgabetyp muss int sein? Anstatt void einfach int?

Vielen Dank für deine Hilfe....ich sitz jetzt seit fast 2 Wochen mehrer Stunden am tag daran und versuch das mathematisch und programmiertechnisch auf die Reihe zu bekommen....


----------



## Mizi Mace (16. Dezember 2008)

Einen wunderschönen guten Tag,

Die Aufgabe besteht also darin, die Nullstelle der von dir gegebenen Formel mittels dem Verfahren Regula Falsi (Sekantenverfahren) zu berechnen.

Wenn ich mir deine Lösung anschaue, dann ist das eher eine Solver-Verfahren. In der ersten do-while-Schleife erhöhst du q um einen winzigen Schritt, solange bis es ins uferlose läuft oder der Funktionswert größer 0 wird. Da du nur sehr kleine Schritte machst, sollte das dann schon deine Lösung sein, was in der zweiten do-while-Schleife (dem eigentlichen Nullstellen-Verfahren) bestätigt wird. Diese Schleife kannst du eigentlich auch weglassen. Das ist aber nicht der Sinn der Aufgabe. Diese besagt, dass du das Sekantenverfahren nutzen sollst.

Dafür musst du zunächst geschickt zwei Stützstellen raten, die möglichst nahe an der tatsächlichen Nullstelle liegen. Je näher du durch das Raten an die Nullstelle herankommst, desto weniger Interationen brauchst du. Natürlich ist das Raten etwas sehr unsicher, daher ist es sinnvoll sich entsprechende Ersatzfunktionen, bei denen die Nullstellen berechenbar sind, für das Raten zu verwenden. In deinem Fall bietet sich folgende Funktion an:

f(q) = r * ( ( q^n - 1 ) - Rn

Diese Funktion hat ihre (positive) Nullstelle bei:

q = nWurzel( Rn / r + 1 )

Achtung! Es gibt auch noch eine negative Nullstelle. Da hier aber (sicherlich) nur positive Lösungen sinnvoll sind, brauchst du diese nicht zu beachten. Als zweite Stützstelle bietet sich die 0 an.

Dann wird das iterative Sekantenverfahren gestartet. Ich gehe davon aus, dass du dieses kennst und anwenden kannst. Wenn das nicht der Fall ist, gibt es hier eine Beschreibung. Bei der Umsetzung und eventueller benötigter Hilfe kannst du natürlich nachfragen.

Gruss
Mizi

Gruss
Mizi


----------



## TRANSformator (16. Dezember 2008)

Hallo,
echt klasse, wie kompetent einem hier geholfen wird....damit hätte ich nicht gerechnet.
Das Problem beginnt bei mir ja schon an der Umsetzung des Regula Falsi Verfahren.
Habe so etwas noch nie gemacht und selbst im Mathe-hauptkurs amchen wir nichst vergleichbares.
Erst im Laufe der Programmierung merkte ich, dass q nicht so eifnach zu berechnen ist und hab mich dann schlau gemacht. Und dann ging das gewurstel los......mittlerweile blicke ich durch q garnicht mehr durch. Uns fehlen sowohl die mathematischen als auch programmiertechnischen Grundlagen und nun sitz ich vor dem Problem, dass ich nicht weiß, wie ich das regula falsi verfahren in programmiersprache umsetzen soll.

Ich habe testweise mal das Newton-Verfahren verwendet udn damit läufts nun auch, nur soll ich halt regula falsi benutzen, bei dem ich völlig auf dem Schlauch stehe.

Ich hab keinen Plan, wie ich das ganze in einen code umsetzen soll.
Wäre schön, wenn du mir da noch ein paar Ansätze geben könntest.

Danke


----------



## ciever2k (16. Dezember 2008)

Mr Apfelkuchen hat gesagt.:


> Diese Schleife wird genau 999.999.999 mal durchlaufen...




Na wir wollen mal nicht vergessen das Rundungsfehler bei Berechnungen mit Float-Werten zu beachten sind  Die Häufigkeit der Iteration kann nur annähernd angenommen werden.

Beispiel:


```
int main( int argc, char **argv ) {
        float q = 0;
        int counter = 0;
        for (q = 1.001; q < 10000; q += 0.001)
                counter++;
        printf("counter: %d\n", counter);
}
```

Sollte eigentlich 9.998.998 Durchläufe machen, aber folgendes ist das Resultat:


```
cr@sattyman:/media/files/programming/c$ time ./rundungsfehler
counter: 10224070

real    0m0.088s
user    0m0.088s
sys     0m0.000s
```


----------



## Mr Apfelkuchen (16. Dezember 2008)

ciever2k hat gesagt.:


> Na wir wollen mal nicht vergessen das Rundungsfehler bei Berechnungen mit Float-Werten zu beachten sind  Die Häufigkeit der Iteration kann nur annähernd angenommen werden.


Ich wollte es nur deutlich machen.... Gut hätte auch ungefähr statt genau
Also sehr oft^^


----------



## Mizi Mace (17. Dezember 2008)

Einen wunderschönen guten Morgen,



TRANSformator hat gesagt.:


> Hallo,
> Uns fehlen sowohl die mathematischen als auch programmiertechnischen Grundlagen und nun sitz ich vor dem Problem, dass ich nicht weiß, wie ich das regula falsi verfahren in programmiersprache umsetzen soll.



Vorab:

Auf jedem Fall erstmal zum Verständnis wäre eine kleine Erläuterung der Formel sinnvoll, insbesondere der Formelzeichen. Einiges konnte man ja im Quellcode ablesen:

Rn ... Rentenendwert
r ... Rate
n ... Laufzeit

Da fehlen nun noch die Variable q und die Gültigkeitsintervalle.

Und nun zu einigen Erläuterungen:

Wollen wir zunächst mit dem mathematischen Teil beginnen. Deim Regula-Falsi-Verfahren geht es darum durch Bildung von Sekanten die Nullstelle einer Funktion annähernd zu bestimmen. Dazu werden zunächst zwei Stützstellen geraten. Eine Stützstellen wird dabei mit 0 angenommen und die andere nach folgender Gleichung berechnet:

q = nWurzel( Rn / r + 1 )

Das Problem an dieser Gleichung ist, dass sie nicht unbegrenzt gültig ist, da diese einen schnittpunkt bei q=2 mit deiner Rentenformel hat. Da stellt sich nun die Frage in welchen Intervallen deine Variablen gültig sind (siehe oben). 

Nun hast du zwei Stützstellen a0 und b0 (Ich halte mich mal an die Syntax von Wikipedia, damit du das direkt vergleichen kannst). Zu diesen Stützstellen kannst du dir die Funktionswerte f(a0) und f(b0) berechnen. Du erhälst zwei Punkte. Durch diese wird eine Gerade gelegt, welche wiederum einen Schnittpunkt mit der q-Achse aufweist. Dies ist c1. c1 kannst du auch einfach über folgende Gleichung berechnen:

c1 = ( a0 * f( b0 ) - b0 * f( a0 ) ) / ( f( b0 ) - f( a0 ) )

Zu den c1 kannst du dir wieder den Funktionswert berechnen. Ist dieser in einer entsprechenden Genauigkeit, kann das Verfahren abgebrochen werden. Andernfalls wird damit fortgefahren. Es wird eine der beiden Stützstellen a0 oder b0 mit c1 ersetzt. Es wird genau diese ersetzt, welche im Funktionswert genau das gleiche Vorzeichen aufweist. Wenn also f( a0 ) das gleiche Vorzeichen hat wie f( c0 ) dann wird a0 ersetzt (b0 analog). Nun hast du zwei neue Stützstellen a1 und b1 (bzw. eine, da die andere gleich geblieben ist). Mit diesen kannst du dir c2 berechnen und somit f( c2 ). Dann überprüfst du wieder, ob das genau genug ist... 

Das ganze geht solange bis die gewünschte Genauigkeit erreicht ist. Im Normalfall kann eine Iteration unter 20 Schritten erwartet werden.

Am besten machst du dir mal ein kleines Beispiel, welches du von Hand auf einen Blatt Papier durchrechnest. Dann hast du es auch wirklich verstanden. Das ganze ist nicht schwer.

Den Programmablauf in Worten habe ich im Prinzip nun auch erklärt. Das Programm könnte dann folgenden Ablauf haben (Achtung, es handelt sich hier nicht um wirklichen Quellcode):


```
// Vorgabe einlesen

// Ermittle Stützstellen a und b durch "Raten" (Hier gibt es noch Klärungsbedarf)
// Ermittle Funktionswerte zu a und b f( a ) und f( b )
// Ermittle neue Stützstelle c
// Ermittle Funktionswert zu c f( c )

while ( f( c ) > Genauigkeit ) {
    // Ermittle a und b durch Ersetzen mit c (Fallunterscheidung notwendig)
    // Ermittle Funktionswerte zu a und b f( a ) und f( b )
    // Ermittle neues c
    // Ermittle Funktionswert zu c f( c )
}

// Berechne Zinssatz
// Ausgabe
```

So in der Art könnte eine verbal ausformuliertes Programm aussehen.

Gruss
Mizi


----------



## TRANSformator (17. Dezember 2008)

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:


```
#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");
}
```


----------



## Mizi Mace (17. Dezember 2008)

Einen wunderschönen guten Tag,

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



TRANSformator hat gesagt.:


> ```
> 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.


```
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.



TRANSformator hat gesagt.:


> ```
> int i;
> i = 1.0;
> ```



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


```
int i;

i = 1;
```

So sieht das besser aus.



TRANSformator hat gesagt.:


> ```
> 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;
> ...





TRANSformator hat gesagt.:


> 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:


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



TRANSformator hat gesagt.:


> 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


----------



## TRANSformator (17. Dezember 2008)

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:


```
#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.


----------



## Mizi Mace (18. Dezember 2008)

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):


```
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


----------



## TRANSformator (18. Dezember 2008)

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ß


----------

