Entwickler-Ecke

Off Topic - C++ Fibonacci


GericasS - Mo 07.12.09 22:08
Titel: C++ Fibonacci
Guten Abend liebe Community,

ich hab heute mit C++ angefangen und mich an der Fibonacci Reihe versucht, sieht wie folgt aus :


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
#include<iostream>
#include<windows.h>

using namespace std;

unsigned int fibonacci(unsigned int zahl)
{
  if (zahl == 0)
  {
    return 0 ;
  }
  if (zahl == 1)
  {
    return 1;
  }
  return fibonacci(zahl-1)+ fibonacci(zahl-2);
}
int main() 
{
    unsigned int zahl;

    cout << "Bitte Zahl eingeben: ";
    cin >> zahl;                                
    cout << "Die Fibonacci-Zahl von " << zahl <<
        " ist " << fibonacci(zahl) << "!" << endl;
  system("Pause");
}


Die main() verstehe ich, aber in der fibonacci Funktion steige ich einfach nicht durch wie er wenn ich als "zahl" z.B die 6 angebe auf die Fibnacci 8 kommt.
Wenn mir vll. jemanden genauer zeigen könnte wie es innerhalb dieser Funktion abläuft wäre ich sehr dankbar.

Vll. so ? fib(6-1)+fib(5-2) usw. ?

LG

GericasS


Gausi - Mo 07.12.09 22:18

Das Prinzip der "Rekursion" ist dir aber geläufig? Hier hat man halt eine baumartige Rekursion, d.h. zur Berechnung werden zwei rekursive Aufrufe hintereinander gestartet - ist für die Laufzeit natürlich nicht gerade toll.
Bei anderen rekursiven Berechnungen wie z.B. der Fakultät hat man nur einen rekursiven Aufruf pro Schritt.


GericasS - Mo 07.12.09 22:23

Ist denn mein Ansatz fuer die beschreibung der funktion richtig ? Ja rekursion ist mir gelaeufig ;)


Gausi - Mo 07.12.09 22:28

Grob, ja. :D

Für die Berechnung von fib(6) wird zunächst fib(6-1) berechnet, danach fib(6-2), das Ergebnis beider Berechnungen wird dann addiert.
Für die Berechnung von fib(6-1) = fib(5) wird zuerst fib(4) und dann fib(3) berchnet. Ja, fib(4) wird doppelt berechnet. So geht das weiter runter.


GericasS - Mo 07.12.09 22:34

Sry aber ich steh grad total aufm schlauch wenn ich fib(6-1) berechne bekomme ich 5 raus und dann bei fib(6-2) bekomm ich 4 raus Oder ? Bitte nicht erschlagen :(


Gausi - Mo 07.12.09 22:41

Nein, die Fibonacci-Zahlen sind so definiert:

0, 1, 1, 2, 3, 5, 8, 13, 21, ... also immer die Summe der beiden vorherigen. Also fib(6-1) = fib(5) = 5 (0 ist die Nullte Fibonacci-Zahl), und fib(6-2) = fib(4) = 3.

6-1 ist 5, und das wird als Argument für die fib-Funktion genommen.


gfoidl - Di 08.12.09 01:04

Hallo,

damit nicht immer alle Werte rekursiv erneut berechnet werden müssen können diese zwischengespeichert und wiederverwendet werden. Sie ändern sich ja nicht. (das führt in Richtung dynamischer Programmierung)

Gruss
Günther


elundril - Di 08.12.09 01:09

also bevor ich hier dynamische Programmierung verwende, verwende ich lieber ne Schleife!

lg elundril


Namenlosnameless - Di 08.12.09 01:37

naja ich bin mir ja nicht so sicher ob ich verstanden habe worum es geht: aber wenn ich mich nicht verlesen habe willst du alle Fibonacci-Zahlen bis zu einer bestimmten ausrechnen lassen??
Das geht aber irgendwie einfacher.

Wobei bei den ganzen Programmierprofis die am Thread teilnehmen habe ich mich sicher geirrt^^

mfg Namenlosnameless


gfoidl - Di 08.12.09 01:46

Zitat:
also bevor ich hier dynamische Programmierung verwende, verwende ich lieber ne Schleife!

Dann hast du wohl dynamische Programmierung nicht richtig verstanden :P
Der Bottom-Up Ansatz der dynamischen Programmierung wäre das was du mit Schleife meinen wirst.
(Vieles was logisch und einfach scheint wurde benamt, so auch hier.)


Gruss
Günther


elundril - Di 08.12.09 01:48

also dyn. Programmierung war, soweit ich AlgoDat1 noch in erinnerung hatte: Rekursion mit einem Array in dem schon gefundene lösungen zwischengespeichert werden und wo man dann einfach nachguckt. Oder hab ich da was falsch in erinnerung bzw falsch verstanden?

lg elundril


gfoidl - Di 08.12.09 02:13

Du hast eher die zweite Art der Interpretation/Anwendung nicht berücksichtigt.

Lass mich die dynamische Programmierung allgemeiner so erklären:

Die Lösungen kleinerer Teilprobleme werden dirket berechnet und zwischengespeichert und zu einer Lösung eines größeren Problems zusammengesetzt.

Somit gibt es die Möglichkeit per Rekursion von der großen Lösung auf die kleineren Lösungen zu kommen (top-down) oder beginnend mit der kleinsten Lösung die größeren zusammenzubauen (bottom-up). Es ist also beiden möglich und verwendet die selbe Technik, welche mit dynamischer Programmierung benamt wurde.

Genau das Beispiel der Fibonacci-Zahlen wird übrigens auch in der engl. Wiki [http://en.wikipedia.org/wiki/Dynamic_programming#Fibonacci_sequence] angeführt.

Gruss
Günther


elundril - Di 08.12.09 03:12

stimmt, stimmt. Danke, wieder was gelernt. :)

lg elundril


Gausi - Di 08.12.09 08:51

@Namenlosnameless: Ja, das geht einfacher. Ein Ansatz wurde ja in den letzten Beiträgen diskutiert. Aber hier geht es wohl um die Funktionsweise dieses Codes da oben. Das ist ein klassisches Beispiel für baumartige Rekursion mit einer absolut tollen Laufzeit. Dagegen geht Bubblesort ab wie Schmidts Katze. ;-)


GericasS - Di 08.12.09 21:14

Abend,

könnte mir bitte nochmal jemand erklären was genau in diesem Abschnitt passiert wenn die Zahl nicht 0 oder 1 ist :


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
unsigned int fibonacci(unsigned int zahl)
{
  if (zahl == 0)
  {
    return 0 ;
  }

  if (zahl == 1)
  {
    return 1;
  }

  return fibonacci(zahl-1)+ fibonacci(zahl-2);
}


Wenn die eingebene Zahl z.b 6 ist !

LG

GericasS


elundril - Di 08.12.09 22:33

in dem abschnitt rufst du die funktion noch mal auf und gibst das ergebnis von den beiden aufrufen zurück.

also fibonacci(5) + fibonacci(4). und die resultate davon gibst du zurück. im fibonacci(5) gibst du dann fibonacci(4) + fibonacci (3) zurück, usw. so lange bist du fibonacci(0) aufrufst. das gibt dann gleich 0 zurück. Wie du demnach siehst eignet sich fibonacci nicht wirklich für rekursionen. ;)

lg elundril


Flamefire - Di 08.12.09 23:51

oder aus wiki:
Zitat:
Notice that if we call, say, fib(5), we produce a call tree that calls the function on the same value many different times:

1. fib(5)
2. fib(4) + fib(3)
3. (fib(3) + fib(2)) + (fib(2) + fib(1))
4. ((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
5. (((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))


Jakob_Ullmann - Mi 09.12.09 19:46

Also ich würde es ja so machen (Pseudocode):


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
prozedur Fibonacci(x: ganzzahl)
wenn x > 2 dann
  Fibonacci(x) = Fibonacci(x - 2) + Fibonacci(x - 1)  
sonst wenn x = 0 dann
  Fibonacci(x) = 0
sonst wenn x <= 2 dann
  Fibonacci(x) = 1
ende prozedur


Ich denke aber, das ganze würde ohne Rekursion trotzdem wesentlich schneller gehen:


Quelltext
1:
2:
3:
4:
5:
fib[0] = 0
fib[1] = 1
fib[2] = 2
für i = 3 bis x tue
  fib[i] = fib[i - 2] + fib[i - 1]


EDIT: Wobei ich jetzt ehrlich gesagt nicht weiß, inwieweit man sowas in C++ umsetzt. Dynamosche Arrays gibt es da ja afaik nicht. Höchstens über Pointer vielleicht...


Gausi - Mi 09.12.09 20:02

Geht auch ohne Arrays - man braucht ja immer nur die letzten beiden Zahlen. ;-)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
vorletzteFib := 0;
letzteFib := 1;

for i := 2 to n do
begin
  neueFib := letzteFib + vorletzteFib;
  vorletzteFib := letzteFib;
  letzteFib := neueFib;
end;
result := letzteFib;