我正在尝试计算第n个斐波那契数模10 ^ 9 + 7,其中n由用户输入。
我用黄金比率来计算斐波纳契数。
以下代码产生正确的结果,直到n = 43。但是对于n> = 44,phi超过10 ^ 9 + 7并且我开始得到意想不到的结果。此外,如果去除模数,则n> = 44给出正确的结果。
#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;
}
为什么会这样?使用long double存储不合理的数字是不对的吗?
由于
答案 0 :(得分:0)
closed form expression for the n'th Fibonacci number是
F n =φ n /√5 - ψ n /√5
,其中
φ= 1/2 +√5/ 2≅1.6180339887
ψ= 1/2 - √5/ 2 =φ - 1≅0.6180339887
由于F n 中的减去部分总是小于一半,我们可以将Fn via rounding计算为零(或朝向负无穷大,或floor()
,因为F对于n≥0, n 是非负的:
F n =⌊φ n /√5⌋= floor(φ n /√5)
如果我们对F n 模M,M≥2感兴趣,我们需要观察modulo operation影响上述公式。请注意,表达式“expr MOD M”通常使用C中的fmod(expr, M)
计算。
我们可以应用property of modular multiplication:正面实数 a , b 和 m ,( a < / em> mod m )( b mod m )=( a b mod m )。地板操作不受影响。这里, a =φ n , b = 1 /√5。这意味着我们可以简化表达式
F n MOD M =⌊φ n /√5⌋MODM
到
F n MOD M =⌊(φ n MOD(M√5))/√5⌋
在这里,我们可以应用modular exponentiation,注意此时的模数不是整数M,而是 M·√5。
换句话说,如果我们有一个函数使用具有浮点模数的模幂运算来执行浮点值的整数次幂,比如说
double pow_mod(double base, unsigned int exponent, double modulus);
我们可以使用
计算第n个斐波那契数F n 模数#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);
right-to-left method是模幂运算的绝佳选择。