用C中的黄金分割比计算n个fibonacci数模m

用C中的黄金分割比计算n个fibonacci数模m,c,fibonacci,modulo,C,Fibonacci,Modulo,我试图计算模为10^9+7的第n个斐波那契数,其中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 i

我试图计算模为10^9+7的第n个斐波那契数,其中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;
}
#包括
#包括
长双模=100000007;
长双电源(长双基地,长长国际博览会)
{
如果(基数=1 | | expo==0)
返回1;
国际单项体育联合会(世博会和第一届)
{
长双温=电源(底座,expo>>1);
返回fmodl(基本*fmodl(温度*temp,mod),mod);
}
其他的
{
长双温=电源(底座,expo>>1);
返回fmodl(温度*温度,mod);
}
}
内部主(空){
//你的密码在这里
长双φ=(1+powl(5,0.5))/2;
长双phi_帽=(1-功率(5,0.5))/2;
长双根5=powl(5,0.5);
长整型n;
scanf(“%lld”、&n);
长双ans=fmodl((功率(φ,n)-功率(φ,n))*功率(root5,mod-2),mod);
printf(“%.0Lf\n”,ans);
返回0;
}
为什么会发生这种情况?使用长双精度存储无理数是错误的吗

谢谢

Fn=φn/√5-ψn/√五,

在哪里

φ=1/2+√5/2 ≅ 1.6180339887
ψ = 1/2 - √5/2 = φ - 1 ≅ 0.6180339887

因为Fn中的减法部分总是小于一半,所以我们可以朝着零计算(或者朝负无穷大计算,或者
floor()
,因为Fn对于n是非负的≥ 0):

Fn=⌊ φn/√5.⌋ = 地板(φn/√(五)

如果我们对模M,M感兴趣≥ 我们需要观察上述公式的影响。请注意,表达式“expr MOD M”通常使用in C计算

我们可以应用:对于正实a,b和m,(a mod m)(b mod m)=(a mod m)。地板操作不受影响。这里,a=φn,b=1/√5.这意味着我们可以简化表达式

Fn模块M=⌊ φn/√5.⌋ MOD M

进入

Fn模块M=⌊ (φn模(M)√5) ) / √5.⌋

在这里,我们可以应用,注意到在这一点上的模不是由整数M,而是由M·√五,

换句话说,如果我们有一个函数,它使用浮点模的模幂运算对浮点值进行整数次幂运算,比如

double pow_mod(double base, unsigned int exponent, double modulus);
我们可以使用

#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);
在这里,是模幂运算的最佳候选者。

Fn=φn/√5-ψn/√五,

在哪里

φ=1/2+√5/2 ≅ 1.6180339887
ψ = 1/2 - √5/2 = φ - 1 ≅ 0.6180339887

因为Fn中的减法部分总是小于一半,所以我们可以朝着零计算(或者朝负无穷大计算,或者
floor()
,因为Fn对于n是非负的≥ 0):

Fn=⌊ φn/√5.⌋ = 地板(φn/√(五)

如果我们对模M,M感兴趣≥ 我们需要观察上述公式的影响。请注意,表达式“expr MOD M”通常使用in C计算

我们可以应用:对于正实a,b和m,(a mod m)(b mod m)=(a mod m)。地板操作不受影响。这里,a=φn,b=1/√5.这意味着我们可以简化表达式

Fn模块M=⌊ φn/√5.⌋ MOD M

进入

Fn模块M=⌊ (φn模(M)√5) ) / √5.⌋

在这里,我们可以应用,注意到在这一点上的模不是由整数M,而是由M·√五,

换句话说,如果我们有一个函数,它使用浮点模的模幂运算对浮点值进行整数次幂运算,比如

double pow_mod(double base, unsigned int exponent, double modulus);
我们可以使用

#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);

在这里,是模幂运算的一个很好的候选者。

问题:使用长双精度存储无理数是错误的吗?答:是的,因为它们只能在一定程度上精确。您可能想看看像GMP这样的库(请参阅)。不能应用于有理数,只能应用于整数。@pytheos:谢谢。但我想它对较低的价格仍然有效values@MOehm:谢谢。这是否意味着不可能使用黄金比例来实现这一点?你能举个例子说明什么时候可以使用fmodl()和fmod()之类的函数吗?为什么你想用这种方式计算斐波那契数?因为你认为它更快?问题:使用长双精度存储无理数是错误的吗?答:是的,因为它们只能在一定程度上精确。您可能想看看像GMP这样的库(请参阅)。不能应用于有理数,只能应用于整数。@pytheos:谢谢。但我想它对较低的价格仍然有效values@MOehm:谢谢。这是否意味着不可能使用黄金比例来实现这一点?你能举个例子说明什么时候可以使用fmodl()和fmod()之类的函数吗?为什么你想用这种方式计算斐波那契数?因为你认为它更快?你能解释一下你是如何从M型升级到Mroot5型的吗?我试过使用,但它可能只适用于整数?@raksh93:我在答案中添加了解释;因为
(a mod m)*(b mod m)=(a*b)mod m
。floor操作不受影响,因为它只是从结果中减去一个较小的值(小于1),而移动模运算根本不会影响要计算的值。至于模幂运算,你真的应该使用,取而代之的是:维基百科页面甚至有伪代码来告诉你怎么做。或者你可以使用节省内存的方法,在同一页上使用之前的伪代码。对于实数,如PHI和SQRT5,模块化算法的效果不太好。你能解释一下你是如何从mod M到mod Mroot5的吗?我试过使用,但它可能只适用于整数?@raksh93:我在答案中添加了解释;因为
(a mod m)*(b mod m)=(a*b)mod m
。地板