Effizientere Lösung: Projekt Euler # 2: Sogar Fibonacci-Zahlen

7

Problem:

  

Jeder neue Ausdruck in der Fibonacci-Sequenz wird durch Hinzufügen der    vorherige zwei Begriffe.

     

Wenn Sie mit 1 und 2 beginnen, werden die ersten 10 Begriffe angezeigt    sei:

     

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

     

Unter Berücksichtigung der Terme in der Fibonacci-Sequenz, deren Werte dies nicht tun    Überschreiten Sie vier Millionen, finden Sie die Summe der gleichwertigen Begriffe.

Mein Code: (funktioniert gut)

%Vor%

Ich suche nach einem effizienteren Algorithmus, um diese Frage zu beantworten. Irgendwelche Hinweise?

    
user262945 30.06.2014, 05:02
quelle

7 Antworten

12

Wenn folgende Regeln berücksichtigt werden:

  

gerade + gerade = gerade

     

gerade + ungerade = ungerade

     

ungerade + gerade = ungerade

     

ungerade + ungerade = gerade

Die Parität der ersten Fibonacci-Zahlen lautet:

  

o o o o o o o e ...

Im Grunde genommen müssen Sie nur drei Schritte machen. Was ist:

%Vor%

Gegeben (a,b,c) Dies ist (b+c,b+2*c,2*b+3*c) .

Das bedeutet, dass wir nur die letzten zwei Zahlen speichern und die angegebene (a,b) , (a+2*b,2*a+3*b) berechnen müssen.

Also (1,2) -> (5,8) -> (21,34) -> ... und immer die letzte zurückgeben.

Dies wird schneller als ein "Filter" -Ansatz arbeiten, da dies die if-Anweisung verwendet, die das Pipelining reduziert.

Der resultierende Code lautet:

%Vor%

Oder der jdoodle (mit Benchmarking, dauert 5 Mikrosekunden mit Kaltstart und durchschnittlich 50 Nanosekunden, basierend auf dem Durchschnitt von 1M mal). Natürlich ist die Anzahl der Anweisungen in der Schleife größer. Aber die Schleife wird ein Drittel der Male wiederholt.

    
Willem Van Onsem 30.06.2014, 05:26
quelle
3

Sie können es nicht viel besser verbessern, jede Verbesserung, die Sie vornehmen, ist vernachlässigbar und hängt von dem Betriebssystem ab, auf dem Sie arbeiten.

Beispiel:
Laufen Sie Ihren Code in einer Schleife 1M mal auf meinem Mac auch 73-75ms (lief es ein paar Mal).
Ändern der Bedingung:

%Vor%

zu:

%Vor%

und es ein paar Mal wieder laufen, habe ich 51-54ms.

  • Wenn Sie dasselbe auf einem anderen Betriebssystem ausführen, könnten Sie (und wahrscheinlich wird) unterschiedliche Ergebnisse erzielen.
  • Auch wenn wir das Obige als Verbesserung betrachten, teilen Sie ~ 20ms in 1M und die "Verbesserung", die Sie für einen einzelnen Lauf erhalten, ist bedeutungslos (~ 20 Nanos).
alfasin 30.06.2014 05:20
quelle
3

unter Annahme von aufeinanderfolgenden Fibonacci-Zahlen

%Vor%

es scheint effizienter zu sein,
zu verwenden ef 0 = 0, ef 1 = 2, ef = ef n-1

    
greybeard 30.06.2014 09:47
quelle
1

Wie ich in meinem Kommentar erwähnt habe, besteht keine Notwendigkeit für weitere Verbesserungen. Ich habe ein paar Messungen gemacht

  • 1000000 mal das Ganze geloopt
  • Messzeit in [ms]
  • ms / 1000000 = ns
  • so sind einzelne Durchlaufzeiten [ns] diese:

    1. [176 ns] - nutzen Sie aus, dass gerade Zahlen jedes dritte sind
    2. [179 ns] - & amp; 1 statt% 2
    3. [169 ns] - & amp; 1 anstelle von% 2 und eliminiert, wenn by -, ^, & amp; amp; [edit1] neuer Code
    4. [105 ns] - nutzen Sie aus, dass gerade Zahlen jede dritte + abgeleitete doppelte Iteration von Fibonaci sind [edit2] neuer Code
    5. [76 ns] - verringerte die Anzahl der Operanden, um den Overhead und den Heap-Abfall zu verringern
  • der letzte gewinnt klar auf meiner Maschine (obwohl ich erwarten würde, dass der erste der Beste sein wird)

  • alles wurde auf Win7 x64 AMD A8-5500 3,2 GHz
  • getestet
  • App ohne Threads 32-Bit-Compiler BDS2006 Trubo C ++

  • 1,2 sind hier in Answers schon schön erwähnt, also kommentiere ich nur 3:

    %Vor%
  • (a ^ 1) negiert das liebste Bit

  • ((a ^ 1) & 1) ist 1 für gerade und 0 für ungerades a
  • - ((a ^ 1) & 1)) ist -1 für gerade und 0 für ungerades a
  • -1 ist 0xFFFFFFFF, daher wird die Andingnummer nicht geändert
  • 0 ist 0x00000000, also wird die anding Nummer 0 sein
  • daher keine Notwendigkeit für if
  • auch anstelle von xor (^) können Sie Negation (!) verwenden, aber das ist viel langsamer auf meiner Maschine

OK, hier ist der Code ( lese nicht weiter, wenn du es selbst codieren willst ):

%Vor%

[edit1] schneller Code hinzufügen

  • CommuSoft schlug vor, mehr als 1 Zahl pro Iteration von Fibonaci zu iterieren, um Operationen zu minimieren.
  • nette Idee, aber Code in seinem Kommentar gibt keine richtigen Antworten
  • Ich habe ein bisschen meins gemacht, also hier ist das Ergebnis:
  • [105 ns] - nutzen Sie aus, dass gerade Zahlen jede dritte + abgeleitete doppelte Iteration von Fibonaci
  • sind
  • das ist fast das Doppelte der Beschleunigung von 1. aus dem es abgeleitet ist
  • suche nach [edit1] im Code oder suche nach // 4.

[edit2] Noch schneller Code hinzufügen - nur einige Variablen und Operationen für mehr Geschwindigkeit neu anordnen - [76 ns] verringerte die Anzahl der Operanden, um den Overhead und den Heap-Abfall zu verringern

    
Spektre 30.06.2014 07:27
quelle
1

Wenn Sie die Fibonacci-Reihe überprüfen, können Sie für gerade Zahlen 2 8 34 144 610 sehen, dass es eine fantastische Beziehung zwischen geraden Zahlen gibt, zum Beispiel:

%Vor%

dies bedeutet, dass als nächstes sogar in Fibonacci wie folgt ausgedrückt werden kann

%Vor%

in Java

%Vor%     
ShreePool 21.10.2016 10:31
quelle
0

Die Antwort für das Projekt Euler Problem 2 ist (in Java):

%Vor%

Dies ist die einfachste Antwort.

    
M. Paranhos 23.04.2016 20:24
quelle
0

F (n) sei die n-te Fibonnaci-Zahl, d. h. F (n) = F (n-1) + F (n-2) Sagen wir, dass F (n) gerade ist, und dann F (n) = F (n-1) + F (n-2) = F (n-2) + F (n-3) + F (n-2)
F (n) = 2F (n-2) + F (n-3) - Dies beweist den Punkt, dass jeder dritte Term gerade ist (wenn F (n-3) gerade ist, dann muss F (n) auch gleich sein)

F (n) = 2 [F (n-3) + F (n-4)] + F (n-3)
= 3F (n-3) + 2F (n-4) = 3F (n-3) + 2F (n-5) + 2F (n-6)

Aus Gl. 1:
F (n-3) = 2F (n-5) + F (n-6) 2F (n-5) = F (n-3) - F (n-6) -
F (n) = 3F (n-3) + [F (n-3) - F (n-6)] + 2F (n-6)
= 4F (n-3) + F (n-6)

Wenn die Folge gerader Zahlen aus jeder dritten Zahl besteht (n, n-3, n-6, ...)

Sogar Fibonacci-Sequenz:

E (k) = 4E (k-1) + E (k-2)


Fib Sequence F = {0,1,1,2,3,5,8 .....}
Gerade Fib-Sequenz E = {0,2,8, .....}
CODE:
 public static long findEvenFibSum(long n){
     long term1=0;
     long term2=2;
     long curr=0;
     long sum=term1+term2;          
        while((curr=(4*term2+term1))<=n){
            sum+=curr;
            term1=term2;
            term2=curr;             
        }
  return sum;
  }
    
FReeze FRancis 30.05.2016 04:14
quelle

Tags und Links