2016-04-17 19 views
0

Ich versuche die n-te Fibonacci-Zahl modulo 10^9 + 7 zu berechnen, wobei n vom Benutzer eingegeben wird.Berechnen der n-ten Fibonacci-Zahl modulo m unter Verwendung des Goldenen Schnitts in C

Ich habe das goldene Verhältnis verwendet, um Fibonacci-Zahlen zu berechnen.

Der folgende Code liefert korrekte Ergebnisse bis n = 43. Aber für n> = 44 geht phi über 10^9 + 7 und ich bekomme unerwartete Ergebnisse. Auch ergibt n> = 44 ein korrektes Ergebnis, wenn der Modul entfernt wird.

#include <stdio.h> 
#include <math.h> 
long double mod=1000000007; 

long double power(long double base, long long int expo) 
{ 
    if(base==1 || expo==0) 
     return 1; 
    if(expo&1) 
    { 
     long double temp = power(base, expo>>1); 
     return fmodl(base * fmodl(temp*temp, mod), mod); 
    } 
    else 
    { 
     long double temp=power(base, expo>>1); 
     return fmodl(temp*temp,mod); 
    } 
} 


int main(void) { 
    // your code goes here 
    long double phi = (1+powl(5, 0.5))/2; 
    long double phi_cap = (1 - powl(5, 0.5))/2; 
    long double root5 = powl(5, 0.5); 
    long long int n; 
    scanf("%lld",&n); 
    long double ans = fmodl( (power(phi, n) - power(phi_cap, n)) * power(root5,mod-2), mod); 
    printf("%.0Lf\n", ans); 
    return 0; 
} 

Warum passiert das? Ist es falsch, lange Doppel zu verwenden, um irrationale Zahlen zu speichern?

Dank

+0

Frage: Ist es falsch, lange Doppel zu verwenden, um irrationale Zahlen zu speichern? Antwort: Ja, es ist so, dass sie nur zu einem gewissen Grad präzise sein können. Vielleicht möchten Sie Bibliotheken wie GMP anschauen (siehe [link] (https://gmplib.org/)). – jboockmann

+0

[Modulare Kongruenz] (https://en.wikipedia.org/wiki/Modular_arithmetic) kann nicht auf rationale Zahlen, sondern nur auf ganze Zahlen angewendet werden. –

+0

@pytheos: Danke. Aber ich denke, es sollte noch für niedrigere Werte funktionieren. – raksh93

Antwort

0

Die closed form expression for the n'th Fibonacci number ist

F n   =   φ n/√5   -   ψ n/√5

wo

φ = 1/2 + √5/2 ≅ 1,6180339887
ψ = 1/2 - √5/2 = φ - 1 ≅ 0,6180339887

Da das subtrahierte Teil in F n ist immer weniger als die Hälfte, wir Fn via rounding gegen Null berechnen können (oder in Richtung negativ unendlich oder floor(), da F n für n ≥ 0 ist nicht negative):

F n = ⌊ φ n/√5 ⌋ = floor (φ n/√5)

Wenn wir in F interessiert sind n Modulo M, M ≥ 2, müssen wir beobachten Die modulo operation beeinflusst die obige Formel. Man beachte, dass der Ausdruck "expr MOD M" typischerweise unter Verwendung von fmod(expr, M) in C berechnet wird

Wir die property of modular multiplication anwenden können: für positive reelle Zahlen a, b und m, ( a mod m) (b mod m) = (a bmod m). Die Bodenoperation ist nicht betroffen. Hier a = n und b = 1/√5.Dies bedeutet, dass wir den Ausdruck

F n MOD M/√5 ⌋ MOD M

in

F n MOD M vereinfachen = ⌊ φ n = ⌊ (φ n MOD (M5))/√5 ⌋

Hier können wir modular exponentiation anwenden, wobei darauf hingewiesen wird, dass der Modul an diesem Punkt nicht durch die ganze Zahl M, sondern durch M · √5 ist.

Mit anderen Worten, wenn wir eine Funktion, die tut eine ganzzahlige Potenz von einem Gleitkommawert mit modularer Potenzierung mit Gleitkommazahlen Modul haben, sagen

double pow_mod(double base, unsigned int exponent, double modulus); 

wir die n-te Fibonacci-Zahl berechnen können, F n Modulo m

#define PHI 1.61803398874989484820458683436563811772 
#define SQRT5 2.236067977499789696409173668731276235441; 

double fn_mod_m; 
unsigned int n, m; 

fn_mod_m = floor(pow_mod(PHI, n, SQRT5 * (double)m)/SQRT5); 

die right-to-left method ist ein ausgezeichneter Kandidat für die modulare Exponentiation mit hier.

+0

Könntest du erklären, wie du von Mod M zu Mod Mroot5 gegangen bist? Ich habe versucht, [diese Methode] (https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Using_Euler.27s_theorem) zu verwenden, aber es funktioniert wahrscheinlich nur für Ganzzahlen? – raksh93

+0

@ raksh93: Ich fügte die Erklärung der Antwort hinzu; weil '(a mod m) * (b mod m) = (a * b) mod m '. Die floor-Operation wird nicht beeinflusst, da sie nur einen kleinen Wert (weniger als eins) vom Ergebnis subtrahiert und das Verschieben der modulo-Operation den Wert für flower() überhaupt nicht beeinflusst. Bei der modularen Exponentiation sollten Sie stattdessen die [Rechts-nach-Links-Methode] (https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method) verwenden: Die Wikipedia-Seite hat sogar einen Pseudocode Du wie. Oder Sie verwenden die speichereffiziente Methode, Pseudocode kurz zuvor auf derselben Seite. –

Verwandte Themen