C++ (Verständnis-) Probleme lösen.

+A -A
Autor
Beitrag
Böötman
Inventar
#1 erstellt: 23. Dez 2011, 14:54
Ich kämpfe derzeit mit diversen C++ Problemen welche es zu lösen gilt. Hinzukommen jede menge Verständnisprobleme meinerseits. Wenn sich jemand halwegs auskennt, kann er sich ja melden. Einige Lösungen hab Ich online schon gefunden jedoch will Ich´s auch begreifen. Es währ schön wenn sich jemand melden würde.

Kernprobleme:
- Fibinacci Zahlengenerator inkl Parameterübergabe
- Primzahlengenerator mit der Funktionsweise des "Siebes des Eratosthenes"

Und noch einiges mehr.
GraphBobby
Stammgast
#2 erstellt: 26. Dez 2011, 02:20
Prinzipiell lassen sich diese beiden Programme als relativ einfache Schleifen programmieren, beim Primzahlensieb kommt noch ein Array dazu.

Wenn du etwas genauere Angaben dazu machst, wie weit deine Projekte fortgeschritten sind, bzw. wo du momentan anstehst, kann ich dir mehr dazu sagen.

lg
Böötman
Inventar
#3 erstellt: 26. Dez 2011, 14:16
Also Ich steh komplett am Anfang und finde diesen eben nicht. Für unseren Dozent ist alles selbstverständlich und genau so läuft der Unterricht ab. Vernünftige Unterlagen gab´s auch nicht, nur eben das Buch vom Dozent welches mit Fehlern gespickt ist. Erschwerend kommt hinzu das er ein "Chaostheoretiker ist".

Also hier die Aufgabe 1:

Die Fibonacci-Zahlen sind durch f0 = 0, f1 = 1, fi+1 = fi + fi–1 für i = 1, 2, 3, ... definiert, d.h. jede Zahl, außer den ersten beiden, ist die Summe der beiden vorangehenden.
Geben Sie die ersten 40 Werte der Fibonacci-Folge in einem Konsolen-Fenster aus. Verwenden Sie hierfür eine Funktion, die den i-ten Wert der Fibonacci-Folge berechnet und über den Funktionsnamen zurückgibt. Dabei soll i als Parameter übergeben werden.
Diese Zahlenfolge geht auf eine Additionsübung des italienischen Mathematikers Fibonacci im Jahr 1202 zurück, der damit die Fortpflanzung von Hasen modellieren wollte.

Da hängt es schon an der Formelerstellung, wie und wo die Parameterübergabe erfolgt weiß Ich auch nicht. Quasi müssten wir von 0 beginnen. Das Programm ist MS Visual Studio 2010 (freeware).
GraphBobby
Stammgast
#4 erstellt: 26. Dez 2011, 15:59
Guten Morgen!

Also ich fange einmal mit der groben Struktur an.

Grundsaetzlich besteht jedes Programm aus Funktionen, die sich gegenseitig aufrufen koennen, wobei auch Parameter uebergeben werden koennen.
Nach dem Starten beginnt dein Programm in der Funktion "main" zu laufen, von dort rufst du weitere Funktionen auf. Funktionen koennen ausserdem einen Rueckgabewert haben, d.h. beispielsweise das Ergebnis einer Rechnung zurueckliefern.

Ein ganz einfaches Beispiel waere ein C-Programm, das einfach zwei Zahlen durch einen Funktionsaufruf addiert:

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[], char* envp[])
{
  int a, b, sum;

  a = 23;
  b = 19;

  sum = add(a, b);

  fprintf(stdout, "Result is %d\n", sum);

  return 0;
}

int add(int x, int y)
{
  int z;

  z = x + y;

  return z;
}


Erstmal laden die #include Zeilen die Definitionen diverser vordefinierter Funktionen, wie z.B. "fprintf" fuer die Konsolenausgabe.

Dann wird die Funktion "main" definiert, in der das Programm zu laufen beginnt. Die Variablen a, b, und sum sind vom Typ "int", also eine Ganzzahl im Bereich von ungefaehr -2 Milliarden bis +2 Milliarden.
a wird auf 23, b auf 19 festgelegt.
Dann wird die Funktion "add" aufgerufen, wobei die Werte von a und b als Parameter uebergeben werden, und das Ergebnis, das "add" zurueckliefert, in der Variable "sum" gespeichert wird. Zum Schluss wird "sum" mit der Funktion "fprintf" am sogenannten Standard-Output ausgegeben (das landet also normalerweise am Bildschirm).

Die Funktion "add" nimmt zwei Werte als int-Variablen x und y entgegen, im Beispiel oben kommt also der Wert von "a" beim Funktionsaufruf von "add" in "x" an, und "b" in "y". Die Variable "z" speichert das Ergebnis der Addition von x und y, und wird anschliessend als Ergebnis der Funktion zurueckgeliefert.

Die Funktion "add" liesse sich bei dem Beispiel oben, da sie recht einfach ist, prinzipiell auch auf das direkte Zurueckliefern des Rechenergebnisses kuerzen:
int add(int x, int y)
{
  return x + y;
}


Eine Fibonacci-Formel-Funktion muesste nun also einen Wert entgegennehmen, der angibt, die wievielte Fibonacci-Zahl die Funktion zurueckliefern soll.
Anschliessend durchlaeuft die Funktion so oft Additionen der zwei letzten Fibonacci-Zahlen, bis sie eben bei dieser Zahl ankommt.
Dafuer eignet sich prinzipiell eine Schleife (z.B. die Instruktionen "for", "while" oder die Kombination "do" und "while"), allerdings ist das ganze gar nicht so einfach, weil die erste und zweite Fibonacci-Zahl ja vordefiniert werden muessen, und die, je nachdem, wie das Programm geschrieben ist, Sonderfaelle darstellen koennen.

Grundsaetzlich gibt es viele Moeglichkeiten, wie man dieses Programm loesen koennte - entweder bei jedem Funktionsaufruf die jeweilige geforderte Fibonacci-Zahl berechnen, oder beispielsweise beim ersten Aufruf alle berechnen und speichern (ausserhalb der Funktion), so dass sie bei weiteren Funktionsaufrufen nur noch aus einer Tabelle (einem sogenannte "Array") zurueckgeliefert werden muessen.

Ich hoffe, das hilft dir erstmal weiter, erste Schritte zu wagen.

Es ist leider per geschriebenem Text im Forum nicht leicht zu erklaeren, nicht umsonst sind Buecher ueber C / C++ recht dick

lg

PS: Das da oben ist uebrigens noch reines C. C++ funktioniert im Wesentlichen genau gleich, ist aber um Konzepte zur objektorientierten Programmierung erweitert.

Das Programm dort oben laeuft natuerlich auch in einer C++-Umgebung. Falls der C++-Compiler einen Fehler ausgibt, wie etwa "add is not defined in this scope", dann sollte vor "int main(int argc, char* argv[], char* envp[])" erst noch eine Definition fuer die Funktion "add" stehen, die dann so aussieht:
int add(int, int);
Das definiert erstmal, dass diese Funktion irgendwo vorhanden ist, dass der Code dafuer aber an einer anderen Stelle steht. Damit kennt sich dann auch der C++-Compiler aus :)


[Beitrag von GraphBobby am 26. Dez 2011, 16:06 bearbeitet]
Böötman
Inventar
#5 erstellt: 27. Dez 2011, 00:16
Das ist unser Standartgerüst:

#define _USE_MATH_DEFINES
#include <iostream>
#include <iomanip>
#include <cmath>
#include <conio.h>
using namespace std;
int main (void)
{


system ("pause");
}

Worin alles untergebracht werden sollte. Leider kenne Ich die normalen C Befehle nicht so das Ich auch hier wieder auf dem Schlauch stehe.

Hier ist eine C++ Lösung meines Problemes nur verstehe ich deren Aufbau nicht:

#include<iostream>

using namespace std;

void shift(int &x,int &y,int z){
x=y;
y=z;
};

int fibonacci(int n){
int a=1,b=0;
for(int i=2;i<n;++i){
cout<<b<<" ";
shift(a,b,a+b);

}
return b;
};

int main(){
int folgen;
cout<<"Wie viele Folgen sollen ausgegeben werden? ";
cin>>folgen;
cout<<fibonacci(folgen)<<endl;
system("pause");
}

1: Es geht schon los mit der Void Shift Zeile, das ist die Parameterzuweisung mit dem Namen "Shift" wobei x,y und z Integer (Ganzzahlige) Zahlen sind. Wofür steht das "&" vorm x und y? Die Zuweisung das X=Y und Y=Z ist verstehe Ich auch nicht.
2: Die eigendliche Berechnung unter "int fibunacci" verstehe Ich nicht, genausowenig wofür das return b am ende steht.
3: Wieso steht das int main ganz unten? Bisher stand bei unseren Übungen "int main (void)" immer ganz am anfang.

Würdest du mir evtl die 4 Programme schreiben und kommentieren? Das wir dann hierüber diskutieren können? Ich hab schon Youtube gequält um zusammenhänge zu erkennen aber die meisten Videos sind leider auf Englisch so das ich mit meinem Schulenglisch nicht weiterkomme. Need Help!!!
GraphBobby
Stammgast
#6 erstellt: 27. Dez 2011, 02:18

Böötman schrieb:
Wofür steht das "&" vorm x und y?


Das sind Referenzen, d.h. dass nicht die Werte der Variablen uebergeben werden, sondern Referenzen darauf. Die Funktion wuerde sonst die Werte, mit denen die fibonacci-Funktion arbeitet, nicht aendern, sondern nur die Werte, mit denen sie selbst arbeitet.


Die Zuweisung das X=Y und Y=Z ist verstehe Ich auch nicht.


Da werden nur die Werte eins weiterverschoben, d.h. beispielsweise:
x = 0, y = 1, gerechnet wird z = x + y = 1.
Dann erfolgt x = y, y = z, d.h.:
x = 1, y = 1, gerechnet wird z = x + y = 2.
Dann das ganze wieder von vorne, usw.


2: Die eigendliche Berechnung unter "int fibunacci" verstehe Ich nicht, genausowenig wofür das return b am ende steht.


Die funktioniert nur, weil sie immer wieder shift() aufruft. Der Rest ist eine Schleife, die immer so lange laeuft, bis sie bei der gewuenschten Zahl ankommt.
Allerdings ist das Programm ohnehin etwas fehlerhaft.


3: Wieso steht das int main ganz unten? Bisher stand bei unseren Übungen "int main (void)" immer ganz am anfang.

Es muss nicht oben stehen, die Reihenfolge, in der die Funktionen in der Datei beschrieben werden, ist eigentlich egal.

Hier erstmal ein einfaches Fibonacci-Programm, das einfach die Fibonacci-Zahlen bis 40 ausgibt:


#define _USE_MATH_DEFINES
#define FIBO_MAX 40

#include <iostream>
#include <iomanip>
#include <cmath>
#include <stdio.h>

using namespace std;

int* fibo  = NULL;

int getFibo(int);

int main(void)
{
    int i;

    for (i = 0; i < FIBO_MAX; ++i)
    {
        cout << getFibo(i) << "\n";
    }

    return 0;
}

int getFibo(int i)
{
    if (fibo == NULL)
    {
        fibo = new int[FIBO_MAX];
        if (fibo == NULL)
        {
            cerr << "Out of memory\n";
            exit(1);
        }
        fibo[0] = 0;
        fibo[1] = 1;

        for (int j = 2; j < FIBO_MAX; ++j)
        {
            fibo[j] = fibo[j - 1] + fibo[j - 2];
        }
    }

    return (i >= 0 && i <= FIBO_MAX) ? fibo : -1;
}


Das Programm funktioniert ungefaehr so:

Es fragt die getFibo()-Funktion 40mal nach der [i]n
ten Fibonacci-Zahl, wobei n von 0 bis 39 steigt.

Die getFibo()-Funktion bemerkt beim ersten Aufruf, dass sie die Zahlen noch nicht kennt, und generiert eine Tabelle mit 40 Zellen fuer Zahlen.
In die erste Zelle (Zelle 0) setzt sie den Wert 0 ein, in die zweite Zelle (Zelle 1) den Wert 1, anschliessend berechnet sie die Werte der Zellen 2 bis 39 durch die Rechnung:
Zelle[n] = Zelle[n - 1] + Zelle[n - 2]

Anschliessend gibt sie die gewuenschte Fibonacci-Zahl zurueck, vorausgesetzt, dass die erste bis vierzigste Zahl verlangt wird (Index 0 bis 39), andernfalls gibt die Funktion einfach den Wert -1 zurueck, um anzuzeigen, dass es die gewuenschte Fibonacci-Zahl nicht kennt (fuer den Fall, dass jemand z.B. die 62te Fibonacci-Zahl abfragen will, obwohl das Programm nur bis zur 40ten rechnet).

Bei jedem weiteren Aufruf der Funktion getFibo() stellt die Funktion fest, dass sie die Fibonacci-Zahlen schon in der Tabelle hat, und holt nur noch die gewuenschte Zahl aus der Tabelle.

Deshalb ist die Tabelle (int* fibo) ausserhalb der Funktionen main() und getFibo() global gespeichert.

Die Zahlen, die getFibo() zurueckgibt, werden dann direkt ausgegeben.


Der eigentlich wichtige Teil, um den sich in dem Programm alles dreht, ist die Tabelle, in der die Fibonacci-Zahlen gerechnet werden.

int* fibo
...definiert einen sogenannten Pointer (eine Speicheradresse), an der eine oder mehrere int-Werte (Ganzzahlen) zu finden sind.
Wenn man fibo mit einem Index verwendet, also z.B. fibo[5], kriegt man dann den Wert an der entsprechenden Stelle in der Tabelle, also hier z.B. die 6te Zahl (weil fibo[0] die 1te ist, ist fibo[5] die 6te - der Index faengt bei 0 an, nicht bei 1).

Mit
fibo = new int[FIBO_MAX];
...wird die Tabelle aufgebaut, d.h. es wird Speicher fuer FIBO_MAX (= 40, siehe die Zeile #define FIBO_MAX 40) Tabellenzellen angefordert.
Das nachfolgende if (fibo == NULL) usw. ist nur Fehlerbehandlung fuer den (seltenen) Fall, dass kein Speicher frei ist, in diesem Fall bricht das Programm ab.

Die kritischen Punkte fuer das Verstaendnis dieses Programms sind, die Funktionsweise der Tabelle zu verstehen, und zu erkennen, wie die Schleifen arbeiten (die Zeilen mit for (...)).


Das waer's erstmal fuer heute, muss mal eine Runde schlafen

lg
Böötman
Inventar
#7 erstellt: 29. Dez 2011, 15:55
Sorry aber da verlier Ich den Überblick...

Ich weiß Ich stell mich blöd an aber stell dir vor du musst deinen Kind das Schnürsenkelbinden beibringen, für dich ist alles simpel aber für den Stöpsel sieht´s gleich wieder ganz anders aus. Könntest du evtl dein obiges Programm Auskommentiert, kommentieren damit es für mich übersichtlicher ist?

Würdest du mir die 4 Aufgaben lösen da mir derzeit die Zeit wegrennt, dikutiert wird weiterhin Ich will´s ja auch verstehen?

Mfg und danke für deine Bemühungen.
GraphBobby
Stammgast
#8 erstellt: 30. Dez 2011, 15:26
Hier erstmal noch eine kommentierte Variante des Primzahlen-Siebs des Eratosthenes.

Wollte ich ohnehin schon immer mal spassweise schreiben.

Allerdings waeren diese Fragen und Antworten in einem C/C++-Forum besser aufgehoben (z.B. http://www.c-plusplus.de/forum/), wir sind hier schon eher off-topic fuer's HiFi-Forum.

Einfache Variante:


/**
 * Sieve of Eratosthenes - Find prime numbers
 * Byte array-based implementation
 * 
 * (Every number in the sieve is represented by one byte in the array that acts as a marker)
 */
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include <iostream>

#define SIEVESIZE 128

using namespace std;

char* sieve = NULL;

int main(int argc, char* argv[], char* envp[])
{
    uint idx, mIdx;
    uint nr;
    uint sieveSizeRt;

    /* generate the sieve table, one byte for every number in the sieve */
    sieve = new char[SIEVESIZE];
    if (sieve == NULL)
    {
        cerr << "Out of memory\n";
        return 1;
    }
    /* set the sieve value of all numbers to 0 */
    for (idx = 0; idx < SIEVESIZE; ++idx)
    {
        sieve[idx] = 0;
    }
    
    /* check every number up to the square root of the greatest number in the sieve,
     * marking non-prime-numbers by setting their sieve value to 1,
     * starting at the number 2, to avoid marking all multiples of 1 (all numbers, bad idea) */
    sieveSizeRt = (uint) sqrt((double) SIEVESIZE);
    for (idx = 1; idx < sieveSizeRt; ++idx)
    {
        /* unmarked numbers are prime number */
        if (sieve[idx] == 0)
        {
            /* set the sieve value of all multiples of that prime number to 1 */
            nr = idx + 1;
            for (mIdx = idx + nr; mIdx < SIEVESIZE; mIdx += nr)
            {
                sieve[mIdx] = 1;
            }
        }
    }
    
    /* run through the entire sieve and output all prime numbers
     * the prime numbers are those that still have their sieve value set to 0 */
    for (idx = 0; idx < SIEVESIZE; ++idx)
    {
        if (sieve[idx] == 0)
        {
            nr = idx + 1;
            cout << nr << "\n";
        }
    }
}


Speichereffiziente Variante fuer Geeks:


/**
 * Sieve of Eratosthenes - Find prime numbers
 * Bitmap-based implementation
 * 
 * (Every number in the sieve is represented by one bit in the bitmap that acts as a marker)
 */
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include <iostream>

/* SIEVESIZE should be a multiple of sizeof(unsigned long), 
 * normally that is either 32 or 64, depending on machine architecture */
#define SIEVESIZE 1024

using namespace std;

unsigned long* sieve = NULL;

uint bitWidth = sizeof(unsigned long) * 8;
uint sieveEl  = SIEVESIZE / bitWidth;
uint rSize    = sieveEl * bitWidth;

int main(int argc, char* argv[], char* envp[])
{
    uint idx, mIdx;
    uint nr;
    uint svIdx, mSvIdx;
    uint rSizeRt;
    unsigned long bVal, mBVal;
    
    sieve = new unsigned long[sieveEl];
    if (sieve == NULL)
    {
        cerr << "Out of memory\n";
        return 1;
    }
    /* set all sieve bits to 0 */
    for (idx = 0; idx < sieveEl; ++idx)
    {
        sieve[idx] = 0;
    }
    
    /* check all numbers up to the square root of the greatest number in the sieve
     * for being prime, and mark all multiples of those primes in the sieve.
     * start with number 2, to avoid marking all multiples of 1 (all numbers, bad idea) */
    rSizeRt = (uint) sqrt((double) rSize);
    for (idx = 1; idx < rSizeRt; ++idx)
    {
        nr     = idx + 1;
        /* calculate array index and bit value of the sieve bit representing that number */
        svIdx  = idx / bitWidth;
        bVal   = ((unsigned long) 1) << (idx % bitWidth);
        
        /* if the bit is unset, then the number is prime
         * check using boolean AND operator */
        if ((sieve[svIdx] & bVal) == 0)
        {
            /* set the sieve bit for all multiples of that prime number */
            for (mIdx = idx + nr; mIdx < rSize; mIdx += nr)
            {
                /* calculate array index and bit value of the sieve bit */
                mSvIdx = mIdx / bitWidth;
                mBVal  = ((unsigned long) 1) << (mIdx % bitWidth);
                /* turn on the sieve bit, using boolean OR operator */
                sieve[mSvIdx] = sieve[mSvIdx] | mBVal;
            }
        }
    }
    
    /* run through the entire sieve and output prime numbers.
     * the prime numbers are those that still have their sieve bit unset */
    for (idx = 0; idx < rSize; ++idx)
    {
        /* calculate array index and bit value of the sieve bit */
        svIdx = idx / bitWidth;
        bVal  = ((unsigned long) 1) << (idx % bitWidth);
        
        /* if the bit is unset, then the number is prime
         * check using boolean AND operator */
        if ((sieve[svIdx] & bVal) == 0)
        {
            nr = idx + 1;
            cout << nr << "\n";
        }
    }
}


PS: Was waeren denn eigentlich die anderen 2 Problemstellungen, du hast bisher nur das Primzahlensieb und die Fibonacci-Folge erwaehnt?


[Beitrag von GraphBobby am 30. Dez 2011, 15:28 bearbeitet]
Böötman
Inventar
#9 erstellt: 30. Dez 2011, 17:41
Vielen vielen Dank, bescheidene Frage: Warum kommentierst du auf Englisch? Ich kann leider nur auf ca 15 Jahre altes Schulenglisch zurückgreifen und da wird´s schon schweineeng.
Was bedeudeuten folgende Befehle:
1: argc
2: argv
3: envp
4: uint (int sind ganzzahlen aber uint sagt mir nichts)
5: idx
6: mIdx
7: cerr

Also 5 und 6 scheinen die Variablen zu sein.

Die komplette Aufgabenstellung kann Ich einstellen, befürchte jedoch das wir dann durcheinander kommen, daher lass Ich´s lieber.
GraphBobby
Stammgast
#10 erstellt: 30. Dez 2011, 22:27

Böötman schrieb:
Vielen vielen Dank, bescheidene Frage: Warum kommentierst du auf Englisch?


Angewohnheit, ich schreibe sehr viel Software, und es ist sozusagen ein ungeschriebenes Gesetz in der IT-Branche, dass man Code immer auf Englisch kommentiert, damit die Kommentare entziffert werden koennen, wenn den Code mal irgendwer in einem fremden Land in die Haende kriegt.

Da fast alle Programmiersprachen selbst auf Englisch basieren (die Instruktionswoerter), und die IT ihren Ursprung in den USA hat, geht die IT-Welt mehr oder weniger davon aus, dass jede/r, der/die programmiert, Englisch kann.


Ich kann leider nur auf ca 15 Jahre altes Schulenglisch zurückgreifen und da wird´s schon schweineeng.


Es wuerde sicher auch sehr helfen, die Englischkenntnisse aufzufrischen, da - wie oben angemerkt - fast alle Source-Codes auf Englisch kommentiert sind, und man kann sehr viel und schnell lernen, indem man gut kommentierten Source-Codes liest.



Was bedeudeuten folgende Befehle:
1: argc
2: argv
3: envp


Das sind Variablen fuer Werte, die man beim Programmstart uebergeben kriegt:
argc - arguments count = Anzahl der Kommandozeilenargumente, die beim Programmstart mitgegeben wurden
argv - argument values = der Text jedes einzelnen dieser Kommandozeilenargumente, abrufbar mit dem jeweiligen Index: argv[0], argv[1], ..., argv[n], ..., argv[argc-1]
envp - environment pointers - Speicheradressen der sogenannten Environment-Variablen, die mit diversen Funktionen abgerufen werden koennen


4: uint (int sind ganzzahlen aber uint sagt mir nichts)

uint ist eine Abkuerzung fuer "unsigned int", also in ohne negative Zahlen.
int geht von -2.147.483.648 bis + 2.147.483.647
uint dagegen von 0 bis +4.294.967.295


5: idx
6: mIdx


Ja, das sind die Variablen, die zum Lesen und Markieren von Zahlen in der Sieb-Tabelle dienen.
idx = Index, mIdx = Marker Index


7: cerr


Das ist der Error-Output-Stream; jedes Programm kriegt normalerweise drei offene Dateien bzw. Streams mit, den Standard-Input, den Standard-Output und den Error-Output.

Normalerweise kriegt man vom Standard-Input Tastatureingaben, kann ueber den Standard-Output auf den Bildschirm schreiben, und ueber den Error-Output ebenfalls.

Das Betriebssystem kann diese Streams aber umleiten (z.B. in Dateien, oder weiterleiten an andere Programme). Man leitet meistens nur Standard-Output um, Error-Output aber nicht, damit man Fehlermeldungen noch sehen kann.


Also 5 und 6 scheinen die Variablen zu sein.

Stimmt, wie oben schon erwaehnt.
Böötman
Inventar
#11 erstellt: 30. Dez 2011, 23:47
Also lt Buschfunk unserer Lerngruppe steht folgende Lösung für Aufgabe 1 bereit:




#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;

double Fibonacci ( int Zahl);
int main ()
{
int i;
cout << "Die ersten 40 Fibonacci-Zahlen lauten:" << endl;
for (i=0; i<40; i++)
{
cout << setw(2) << i << " => " << setw(20) << Fibonacci(i) << endl ;
}
system ("Pause");
return 0;
}
double Fibonacci (int Zahl)
{
double Fib[40];
int n;
Fib [0]=0;
Fib [1]=1;
for (n=2; n<40; n++)
Fib[n]=Fib[n-1]+Fib[n-2];
return Fib[Zahl];
}

Was macht dieser passus und wie kommt man drauf? "(i=0; i<40; i++)", Ich vermute das der Bearbeitungsbereich von i=0 bis i<40 festgelegt wird, nur was macht i++?
Komplettes Unverständnis umgibt mich bei der eigendlichen Fibunacciberechnung, wie kommt man darauf und was macht jede Zeile?

Teilweise verstehe Ich´s, nur der zusammenhang fehlt:

"double Fib[40]" -> Festlegung von 40 Speicherplätzen im Zahlentyp double
"system ("Pause");" und "return 0;" Warum steht das da oben und nicht ganz am ende???
"int n;" -> Festlegung das immer ganzzalig weitergezählt wird, i wurde von oben übergeben und existiert hier als n weiter
"Fib [0]=0;" und "Fib [1]=1;" legen die Startbedingungen fest
"for (n=2; n<40; n++)
Fib[n]=Fib[n-1]+Fib[n-2];
return Fib[Zahl];" Hier fehlt mir das komplette Verständnis.
svelte
Hat sich gelöscht
#12 erstellt: 31. Dez 2011, 00:49

Böötman schrieb:
Was macht dieser passus und wie kommt man drauf? "(i=0; i<40; i++)", Ich vermute das der Bearbeitungsbereich von i=0 bis i<40 festgelegt wird, nur was macht i++?


Den Wert von "i" um "1" erhöhen. "i++" ist die verkürzte Schreibweise von "i=i+1".

Das Konstrukt an sich ist eine (for-) Schleife. Der Teil innerhalb der nachfolgenden geschweiften Klammern wird solange wiederholt wie die Bedingung "i < 40" zutrifft.

Als Startwert für "i" wird "0" definiert ("i=0"), dann in jedem Durchlauf "i" um "1" erhöht ("i++").

Die Definition der for-Schleife ist so vorgegeben.

Ich vermisse bei dir sämtliche Grundlagen, ich bezweifle dass Du so den Einstieg findest. Ist es denn wichtig dass Du Programmieren lerns - dann musst Du dir Etwas überlegen, zunächst mal ein einführendes Buch besorgen (ich kann dir gerne eines schicken).
Böötman
Inventar
#13 erstellt: 31. Dez 2011, 12:06
Das Programmieren ist ein kleiner Teilbereich vom Berufsbegleitenden Ingenieursstudium. Daher muss Ich mich zwangsläufig damit auseinandersetzen obwohl mir das Thema absolut nicht liegt. Bin einfach zu alt dafür.

Das das ne For - Schleife ist hab Ich gesehen, aber nicht explizit danebengeschrieben. Meine Auffassung der Formel hab Ich - soweit für mich verständlich - oben aufgeführt, nur bei den zusammenhängen hapert´s. Und genau dort bitte Ich um mithilfe. Das Interesse besteht dass zu begreifen sollte an sich klar sein da mehrere Lösungen hier stehen, Ich aber weiterhin fragen stelle.

Inwieweit liege Ich hier richtig?
1: "double Fib[40]" -> Festlegung von 40 Speicherplätzen im Zahlentyp double
2: "system ("Pause");" und "return 0;" Warum steht das da oben und nicht ganz am ende???
3: "int n;" -> Festlegung das immer ganzzalig weitergezählt wird, i wurde von oben übergeben und existiert hier als n weiter
4: "Fib [0]=0;" und "Fib [1]=1;" legen die Startbedingungen fest
5: "for (n=2; n<40; n++)
Fib[n]=Fib[n-1]+Fib[n-2];
return Fib[Zahl];" Hier fehlt mir das komplette Verständnis.


Ich hoffe trotzdem auf eure Mithilfe. Mittlerweile habe Ich alle vier Lösungen der Übungsaufgaben und würde gern drüber diskutieren wie das alles zusammen Funktioniert, Aufgabe für Aufgabe.
svelte
Hat sich gelöscht
#14 erstellt: 31. Dez 2011, 15:39

Böötman schrieb:
Das das ne For - Schleife ist hab Ich gesehen, aber nicht explizit danebengeschrieben.


Nur wundert man sich wenn Du dann fragst was "i++" macht. Insbesondere wenn die Sprache c++ heisst


Böötman schrieb:

1: "double Fib[40]" -> Festlegung von 40 Speicherplätzen im Zahlentyp double


Ja, so könnte man das ausdrücken. "Fib" wird als Array mit 40 Positionen initialisiert.


Böötman schrieb:

2: "system ("Pause");" und "return 0;" Warum steht das da oben und nicht ganz am ende???


Das steht genau genommen am Ende, denn danach kommt nur noch eine Funktion ("Fibonacci"), die nur aus der Funktion "main()" aufgerufen wird.

Der Ablauf ist nicht von oben nach unten - vom Start weg wird zur Funktion "main()" gesprungen, ganz egal wo die "steht".

Das Programm endet am Ende der Funktion "main()".


Böötman schrieb:

3: "int n;" -> Festlegung das immer ganzzalig weitergezählt wird, i wurde von oben übergeben und existiert hier als n weiter


"i" wird an die Funktion "Fibonacci" übergeben, aber nicht als "n", sondern unter dem Namen "Zahl".

"n" dient hier wie oben "i" nur als Laufvariable für die for-Schleife.


Böötman schrieb:

4: "Fib [0]=0;" und "Fib [1]=1;" legen die Startbedingungen fest


Startbedingungen?


Böötman schrieb:

5:

for (n=2; n<40; n++)
Fib[n]=Fib[n-1]+Fib[n-2];
return Fib[Zahl];

Hier fehlt mir das komplette Verständnis.


Was ein Array ist, weisst Du aber?

Fib[n] ist der Wert des Arrays "Fib" an Position "n".

"n" ändert sich ja bei jedem Durchlauf der Schleife.

Im ersten Durchlauf hat "n" den Wert "2".

1. Durchlauf:
Fib[2] = Fib[1] + Fib[0]

Mit eingesetzten Werten:
Fib[2]= 1 + 0;

Ergebnis:
Fib[2]=1;


2. Durchlauf ("n" hat nun den Wert "3"):
Fib[3] = Fib[2] + Fib[1]

Mit eingesetzten Werten:
Fib[3]= 1 + 1;

Ergebnis:
Fib[3]=2;


3. Durchlauf ("n" hat nun den Wert "4"):
Fib[4] = Fib[3] + Fib[2]

Mit eingesetzten Werten:
Fib[4]= 2 + 1;

Ergebnis:
Fib[4]=3;


4. Durchlauf ("n" hat nun ...):
Fib[5] = Fib[4] + Fib[3]

Mit eingesetzten Werten:
Fib[5]= 3 + 2;

Ergebnis:
Fib[5]=5;


5. Durchlauf:
Fib[6] = Fib[5] + Fib[4]

Mit eingesetzten Werten:
Fib[6]= 5 + 3;

Ergebnis:
Fib[6]=8;


6. Durchlauf:
Fib[7] = Fib[6] + Fib[5]

Mit eingesetzten Werten:
Fib[7]= 8 + 5;

Ergebnis:
Fib[7]=13;


Usw...
mar2000
Stammgast
#15 erstellt: 31. Dez 2011, 15:41
Hallo,

ich versuch mal Deine Fragen zu beantworte, vielleicht hilft Dir das. Ich muss aber svelte recht geben, die fehlen massive Grundkenntnisse und dadurch hast Du eine enorme Wissenslücke zu den Aufgaben - Du solltest Dir da schleunigst einiges an Grundlagenwissen aneignen - es wird vermutlich nicht alleine reichen dass wir Dir hier erklären wie die Aufgaben funktionieren (so viel Text kann vermutlich hier keiner schreiben).


2: "system ("Pause");" und "return 0;" Warum steht das da oben und nicht ganz am ende???

c++ ist (weitgehend) objektorientiert, darum werden die Methoden eines Objektes in c++ nicht von oben nach unten abgearbeitet - die Reihenfolge ist egal. nur innerhalb der Methoden und Eigenschaften (also main () oder Fibonacci (int Zahl) ) wird vom Interpreter Zeile für Zeile gearbeitet. Wie die Methoden in der Datei angeordnet werden ist ein wenig von der jeweiligen "Programmierphilosophie" abhängig, meist wird aber die main () eher am Anfang zu finden sein.


"double Fib[40]" -> Festlegung von 40 Speicherplätzen im Zahlentyp double

In etwa richtig, Du legst den Speicher für ein Array mit 40 Plätzen vom Typ double fest (Arrays beginnen in c immer bei 0).


3: "int n;" -> Festlegung das immer ganzzalig weitergezählt wird, i wurde von oben übergeben und existiert hier als n weiter

Hier wird ein Speicherbereich für eine integer namens "n" festgelegt. i und n haben nichts miteinander zu tun. i wird der Funktion als "Zahl" übergeben, und zwar als Kopie und nicht als Referenz (siehe GraphBobby's Erläuterung zum Thema "& vorm x".

Eine Anmerkung dazu: Eine der größten Schwierigkeiten für Einsteiger in c/c++/objective-c etc. ist immer das Konzept der Belegung von Speicherbereichen und den darauf zeigenden Pointern - insbesondere wenn es darum geht wann man nur eine Referenz übergibt und wann nicht. Du musst dieses Konzept unbedingt in seinen Grundprinzipien verstehen und solltest Dir dazu auf jeden Fall entsprechende Literatur anlesen (da dürfte sich auch online einiges finden)


4: "Fib [0]=0;" und "Fib [1]=1;" legen die Startbedingungen fest

Fib [0]=0; legt fest dass die position 0 des Arrays "Fib" den Wert 0 hat, dito für Fib [1] = 1,


5: "for (n=2; n<40; n++)
Fib[n]=Fib[n-1]+Fib[n-2];
return Fib[Zahl];" Hier fehlt mir das komplette Verständnis.

die drei Zeilen gehören nicht direkt zusammen


5: "for (n=2; n<40; n++)
Fib[n]=Fib[n-1]+Fib[n-2];


beschreibt eine for-next schleife mit dem parameter "n", die Klammer gibt an dass n den Startwert 2 hat, die Schleife beendet wird wenn n<40 NICHT MEHR gilt und n am Ende jedes Durchlaufes um 1 erhöht wird (n++).
Die Nächste Zeile beschreibt was in dieser Schleife bei jedem Durchlauf ausgeführt wird.


return Fib[Zahl];

return gibt immer den Rückgabewert einer Methode an. Eine Methode die return "Hallo" am Ende stehen hat würde Hallo zurückgeben, return 1 würde z.B. 1 zurück geben. In Deinem Fall gibt die Methode am Ende den Wert des Arrays an der Position "Zahl" zurück, für Zahl=3 wäre das z.B. Fib [3], also die Zahl 2.

Edit: das hat sich jetzt mit dem Beitrag von svelte überschnitten... aber ich glaube das ergänzt sich ganz gut.


[Beitrag von mar2000 am 31. Dez 2011, 15:45 bearbeitet]
svelte
Hat sich gelöscht
#16 erstellt: 31. Dez 2011, 16:28
Noch als kleine Erweiterung. Die Funktion "Fibonacci" berechnet immer alle 40 Fibonacci-Zahlen, auch wenn z.B. ja nur die 13. Zahl gefordert wurde. Das ist eine ziemliche Verschwendung an Rechenzeit. Im Idealfall kommt man mit 38 Berechnungen aus, bei der gezeigten Lösung sind es 1520.

Im Aufruf der Schleife sollte daher "40" gegen den Übergabewert "Zahl" getauscht werden, aus "<" wird dazu "<=" (kleiner oder gleich):

double Fibonacci (int Zahl)
{
double Fib[40];
int n;
Fib [0]=0;
Fib [1]=1;
for (n=2; n <= Zahl; n++)
Fib[n]=Fib[n-1]+Fib[n-2];
return Fib[Zahl];
}

D.h., die Schleife läuft nur noch bis zur gesuchten Zahl und berechnet nicht nutzlos alle weiteren Zahlen.

Idealerweise würden die bereits berechneten Zahlen auch nicht jedes Mal erneut berechnet, aber das führt hier wohl zu weit.
Böötman
Inventar
#17 erstellt: 03. Jan 2012, 20:38
Es gibt neuigkeiten: Ich war fleißig und hab mit nem Kollegen rumgetüftelt.

Quelltext Aufgabe 1:


#include <iostream>
#include <cmath>
#include <iomanip>
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <conio.h>
using namespace std;
int fib(int n);
int main()
{
int i;
cout << "Praktikum Informatik 1 (WS 2011/2012)" << endl;
cout << "Aufgabe 1: Ausgabe der ersten 40 Fibonaci Zahlen" << endl;
cout << "Verfasser: *********** (Matrikel: *******)" << endl;
cout << " "<< endl;
cout <<"Die Zahlen lauten: " << endl;
cout << " "<< endl;
for (i=0; i<40; i++)
{
cout << setw(2) << i << " : " << setw (8) << fib(i) << endl;
}

system("pause");
return 0;
}

int fib(int n)
{
if(n==2 || n==1) return 1;
if(n>=3)
return (fib(n-1) + fib(n-2));
}


Feedback ist durchaus erwünscht.
Böötman
Inventar
#18 erstellt: 03. Jan 2012, 20:59
Lösung Aufgabe 2 (Priemzahlenermittlung im Bereich 1-100):

#include <iostream>
#include <cmath>
#include <iomanip>
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <conio.h>
using namespace std;


int main()
{
cout << "Praktikum Informatik 1 (WS 2011/2012)" << endl;
cout << "Aufgabe 2: Priemzahlen (1-100)" << endl;
cout << "Verfasser: ************" << endl;
cout << " "<< endl;

int a, b;
bool Zahl[101];

for (a=1; a<=100 ; a++)
Zahl[a]=true;
for (a=2; a<10 ; a++)
{
for (b=a; a*b<=100 ; b++)
Zahl[a*b]=false;
}

cout << "Die Primzahlen in dem Bereich 1 bis 100 lauten:" << endl;
cout << " "<< endl;
b=0;
for (a=1; a<101 ; a++)
{
if (Zahl[a])
{
b++;
cout <<setw(5) << a ;
if (b%10==0)
cout << endl;
}
}
cout << endl;
cout << " "<< endl;
system ("Pause");
return 0 ;
}
svelte
Hat sich gelöscht
#19 erstellt: 04. Jan 2012, 07:10

Böötman schrieb:
Feedback ist durchaus erwünscht.


Eigentlich hätte man eher von Dir ein Feedback erwartet...

Zur Fibonacci-Lösung: Selten so Etwas gesehen. Ihr macht für "jeden Wert jeder Fibonacci-Zahl" einen Aufruf der Funktion "fib" - ist Euch das eigentlich bewusst? Das sind ~160.000.000 (160 Mio) Aufrufe - so ungefähr jedenfalls.


[Beitrag von svelte am 04. Jan 2012, 07:11 bearbeitet]
Böötman
Inventar
#20 erstellt: 04. Jan 2012, 09:00
Das ist mir durchaus bewusst, die Rechenzeit bestätigt das auch. (hab´s mir Spaßenshalber mal ausgeben lassen und das waren große Zahlen).

Die Aufgabe wurde - wenn auch unkonventionell mit mir bekannten Befehlen - gelöst und mein Verständnis wurde verbessert. Jetzt kann Ich sogar was mit deinen Erklärungen anfangen und das ist doch schonmal was oder?

Ich hab aber noch probleme bei anderen Aufgaben. Einmal sollen wie Pi mit der Regentropfenmethode berechnen, jedoch müssen bei meiner Version immer 0,04 vom Endergebnis abgezogen werden um ein vernünftiges Ergebnis zu erhalten, dazu aber später mehr.
Suche:
Das könnte Dich auch interessieren:
C Programm Watchdog
as_krypton am 17.01.2012  –  Letzte Antwort am 17.03.2012  –  2 Beiträge
jdownloader probleme
seppl209 am 03.06.2010  –  Letzte Antwort am 03.06.2010  –  2 Beiträge
Graka Probleme
entspann0r am 29.04.2014  –  Letzte Antwort am 10.06.2014  –  2 Beiträge
Cinema-Format Probleme
werner_32_ am 25.03.2012  –  Letzte Antwort am 26.03.2012  –  3 Beiträge
Probleme mit Handbrake
BeatMeikl am 07.09.2013  –  Letzte Antwort am 07.09.2013  –  3 Beiträge
Probleme mit rtf. Dateil
Blechdackel am 26.06.2019  –  Letzte Antwort am 02.07.2019  –  4 Beiträge
Probleme mit Browsergame / Adobe Flashplayer
entspann0r am 05.09.2011  –  Letzte Antwort am 28.09.2011  –  7 Beiträge
Avira AntiVir Personal - Free Antivirus: durchsucht wirklich nur C:/ ?
Soundy_man am 24.12.2010  –  Letzte Antwort am 09.01.2011  –  10 Beiträge
Cookie-Shield-Scanner : Test ob ne Webseite C. setzt?
swiss_fan_of_revox am 23.02.2023  –  Letzte Antwort am 25.02.2023  –  2 Beiträge
Probleme beim Verkauf der DIRAC-Lizenzen
mx300 am 10.06.2014  –  Letzte Antwort am 30.06.2014  –  237 Beiträge
Foren Archiv
2011
2012

Anzeige

Produkte in diesem Thread Widget schließen

Aktuelle Aktion

Partner Widget schließen

  • beyerdynamic Logo
  • DALI Logo
  • SAMSUNG Logo
  • TCL Logo

Forumsstatistik Widget schließen

  • Registrierte Mitglieder925.721 ( Heute: 1 )
  • Neuestes MitgliedBluebyte75.
  • Gesamtzahl an Themen1.551.069
  • Gesamtzahl an Beiträgen21.537.341

Hersteller in diesem Thread Widget schließen