Einzelnen Beitrag anzeigen

Benutzerbild von glkgereon
glkgereon

Registriert seit: 16. Mär 2004
2.287 Beiträge
 
#1

Fibonacci in 6 Versionen

  Alt 13. Apr 2005, 18:00
Hi!

In einer angeregten Disskussion über verschiegene Algorithmen zur Errechnung einer bestimmten Fibonacci-Zahl kamen folgende 6 Lösungen heraus:
- Iterativ
- Rekursiv
- Formel
- Assembler
- Hagen 1
- Hagen 2

Die iterative Lösung
Autor: glkgereon
Kommentar: Recht gute Performance, gut zu verstehen
Geschwindigkeit:
25000 16ms
50000 47ms
75000 108ms

Delphi-Quellcode:
function Fibonacci_Iterativ(Index: Integer):Integer;
var i:Integer;
  Last, New: Integer;
begin
  NSet(Result,1);
  NSet(New,1);
  for i:=2 to Index do
  begin
    Last:=Result;
    Result:=New;
    NAdd(New,Result,Last);
  end;
end;

Die Rekursive Lösung
Autor: leddl
Kommentar: deutlich langsamer, sehr gut zu verstehen
Geschwindigkeit:
30 16ms
35 156ms
40 1750ms

Delphi-Quellcode:
function Fibonacci_Rekursiv(Index : Integer) : Int64;
begin
  case Index of
    1, 2 : Result := 1;
    else Result := Fibonacci_Rekursiv(Index-2) + Fibonacci_Rekursiv(Index-1);
  end;
end;

Die Formel-Lösung
Autor: Elite
Kommentar: kompliziert zu verstehen, ab 85 Rundungsfehler
Geschwindigkeit:
85 0ms

Delphi-Quellcode:
function Fibonacci_Formel(Index : Integer) : Int64;
begin
  result := round((1/sqrt(5))*(power((1+sqrt(5))/2, index-1)-power((1-sqrt(5))/2,index-1)));
end;

Die Assembler-Lösung
Autor: Chimaira
Kommentar: flott, leider nur bis 46, da Speicherüberlauf
Geschwindigkeit:
46 0ms

Delphi-Quellcode:
function Fibonacci_Asm(von: Integer): Integer;
  asm
    push eax
    push ebx
    push ecx
    push edx
    mov ecx, von
    mov eax, 1
    mov ebx, 0
    cmp ecx, 2
    jbe @@endoffib
    sub ecx, 1
    @@startLoop:
    mov edx, ebx
    mov ebx, eax
    add eax, edx
    sub ecx, 1
    jnz @@startLoop
    @@endoffib:
    mov result, eax
    pop edx
    pop ecx
    pop ebx
    pop eax
end;

Die Hagen-Lösung 1
Autor: negaH
Kommentar: schnell, und für riesige Zahlen, aber kompliziert
Geschwindigkeit:
500.000 31ms
1.000.000 93ms
5.000.000 515ms

Delphi-Quellcode:
procedure NFibonacci(var R: Integer; N: Cardinal);
var
  T,E,F: Integer;
  Mask: Cardinal;
begin
  if N = 0 then
  begin
    NSet(R, 0);
    Exit;
  end;
  NSet(F, 1);
  Mask := 1 shl Log2(N);
  while Mask > 1 do
  begin
    Mask := Mask shr 1;
    NAdd(T, F, E);
    NSqr(E);
    NSqr(T);
    NSqr(F);
    NSub(T, E);
    NAdd(E, F);
    if N and Mask <> 0 then
    begin
      NSwp(T, E);
      NAdd(T, E);
    end;
    NSwp(T, F);
  end;
  NSwp(F, R);
end;

Die Hagen-Lösung 2
Autor: negaH
Kommentar: superschnell

Delphi-Quellcode:
function Fibonacci_Hagen2(N: Byte): Int64;

function Log2(A: Cardinal): Cardinal; register;
  asm
    BSR EAX,EAX
end;

var
  E,F,T,S: Int64;
  M: Byte;
begin
  M := 1 shl Log2(N);
  F := 1;
  E := 0;
  while M > 1 do
  begin
    M := M shr 1;
    T := E * F;
    F := F * F;
    E := E * E + F;
    T := T + T + F;
    if N and M <> 0 then
    begin
      S := E;
      E := T;
      T := T + S;
    end;
    S := T;
    T := F;
    F := S;
  end;
  Result := F;
end;
Zusammenfassung:

Geschwindigkeit im Überblick(in ms):
Code:
Algo     ||  10       |  20       |  50       |  92       |  100      |  1000    |  10000

Iterativ ||  0,003953 |  0,006155 |  0,013375 |  0,022969 |  0,024531 |  0,24155 |  3,7625

Rekursiv ||  0,002609 |  0,113329 |           |           |           |          |

Formel   ||  0,002235 |  0,002265 |  0,002297 |           |           |          |

Assembler ||  0,001686 |  0,001717 |           |           |           |          |

Hagen 1   ||  0,003828 |  0,004421 |  0,005172 |  0,005795 |  0,005811 |  0,00953 |  0,092

Hagen 2   ||  0,001843 |  0,001906 |  0,001983 |  0,002062 |           |          |
Für die normale Anwendung ist Hagens zweite Lösung am besten / schnellsten, für große Zahlen seine Erste.
Will man jedoch den Quellcode verstehen, so sollte man bei kleinen Zahlen < 35 auf die Rekursive, bei großen Zahlen auf die Iterative zurückgreifen.

Bemerkungen:
Die Tests wurden auf folgendem System gemacht: AMD 2600, 768 MB DDR RAM, Windows 2000
Die Zahlen müssen folgendermaßen gelesen werden: X Y ms "für die X'te Fibonaccizahl brauch dieser Algorithmus Y Millisekunden."

für alle Varianten ausser der Iterativen und der Hagen1 empfehle ich einen Abfang zu hoher bzw zu niediger Zahlen.

Delphi-Quellcode:
if N < 2 then raise Exception.Create('Fibonacci(N), N must be > 1');
if N > 92 then raise Exception.Create('Fibonacci(N),N must be < 93');
Hagens und meine (die Iterative Lösung) brauchen den im DEC von Hagen Reddmann enthaltenen Typ IInteger sowie die zugehörigen Funktionen. Mit diesem sind sehr große Zahlen möglich.

Es folgte noch eine Ergänzung von negaH:
Zitat von negaH:
Naja alternativ gibts ja noch die ganz schnelle Variante. N kann je bei Int64 nur bis 92 gehen.
Delphi-Quellcode:
function FibX(N: Byte): Int64;
const
  nFib: array[0..92] of Int64 =
    (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181,
     6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040,
     1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986,
     102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903,
     2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099,
     53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879,
     956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723,
     17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994,
     190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657,
     2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676221,
     23416728348467685, 37889062373143906, 61305790721611591, 99194853094755497, 160500643816367088,
     259695496911122585, 420196140727489673, 679891637638612258, 1100087778366101931,
     1779979416004714189, 2880067194370816120, 4660046610375530309, 7540113804746346429);
begin
  if N > 92 then raise Exception.Create('N must be < 93');
  Result := nFib[N];
end;
Und hier findet man eine Beschreibung zu dem Algo. den ich in meiner Lib benutzt habe:
http://www.mcs.surrey.ac.uk/Personal...ula.html#exact

Gruß hagen
[edit=flomei]formatiert und korrigiert. Sollten noch Verbesserungs- / Änderungswünsche bestehen bitte eine PN an mich senden. Mfg, flomei[/edit]
[edit=Matze]Code formatiert. Mfg, Matze[/edit]
[edit=Dax]Kleiner Fehler korrigiert. bedah, Dax[/edit]
»Unlösbare Probleme sind in der Regel schwierig...«
  Mit Zitat antworten Zitat