我正在尝试计算第n个fibonacci数,模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("%.0Lfn", ans);
return 0;
}
为什么会发生这种情况?使用长双精度来存储无理数是错误的吗?
感谢
第n个Fibonacci数的闭式表达式是
Fn= φn/√5 - ψn/√5
其中
φ=1/2+√5/2Ş1.6180339887
ψ=1/2-√5/2=φ-1Ş0.6180339887
由于Fn中的被减法部分总是小于一半,我们可以通过向零取整(或者,向负无穷大取整,或者floor()
取整,因为Fn对于n≥0是非负的)来计算F2:
Fn=⌊φn/√5⌋=地板(φn>/√5)
如果我们对Fn模M,M≥2感兴趣,我们需要观察模运算对上述公式的影响。注意,表达式"expr MOD M"通常使用C.中的fmod(expr, M)
计算
我们可以应用模乘法的性质:对于正实数a、b和m,(amodm)(bmodm-。地板操作不受影响。这里,a=φn,b=1/√5。这意味着我们可以简化表达式
FnMOD M=⌊φn/√5⌋MOD M
进入
FnMOD M=⌊(φnMOD(M√5))/√5⌋
在这里,我们可以应用模幂运算,注意这一点上的模不是通过整数M,而是通过M·√5。
换句话说,如果我们有一个函数,它使用浮点模的模幂运算来计算浮点值的整数幂,比如
double pow_mod(double base, unsigned int exponent, double modulus);
我们可以使用计算模m的第n个Fibonacci数Fn
#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);
从右到左的方法是模幂运算的一个很好的候选者。