Programmierung einer do-while Schleife in C

TRANSformator

Grünschnabel
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?

Code:
#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
 
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):p
Da ich die Aufgabe des Programms nicht ganz durchschaue würde ich dich bitten einmal zu beschreiben was das Programm genau tun soll :)
 
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 .....
 
Hi.
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.
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!
 
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.

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


Code:
#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....
 
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
 
Zuletzt bearbeitet:
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
 
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:

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

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

real    0m0.088s
user    0m0.088s
sys     0m0.000s
 
Einen wunderschönen guten Morgen,

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

C:
// 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
 
Zurück