大数字的斐波那契算法

Fibonacci Algorithm for big numbers

本文关键字:算法 数字      更新时间:2023-10-16

寻找解决Fibonacci问题的好算法递归方式给我超过的时间限制

样本输入:70007采样(最后一位):3

这更多的是一道数学题,最近也发布了类似的问题。斐波那契数可以被认为是一个线性递归方程(递归定义)。在这种情况下,F(n)=F(n-1)+F(n-2)。使用数组f来表示f(n)和f(n-1),其矩阵形式为:

       | 1  1 |
   a = | 1  0 |
       | 1 |
f(2) = | 1 |
f(i+1) = a f(i)
f(i+j) = a^j f(i)

这是基于F(0)=0,F(1)=1,F(2)=1,F.(3)=2,F.(4)=3,F.(5)=5,F。。。

为了加快这个过程,通过使用重复平方将矩阵a提高到j的幂。例如,a^7=(a*a^2*a^4)。对于32位n,循环数为32。对于64位n,循环数为64。

然而,由于只要求最后一个数字,所以你以模10进行计算,并且以模10计算,结果是a^(j%60)=a^j(这是使用程序确定的)。

f(i+j) = a^(j%60) f(i)

因此计算a^(j%60)的循环数最多为6。在我的系统上,计算任何32位或64位无符号整数n的fib(n)%10需要不到2微秒的时间,因为实际计算是f(n)=(a^((n-2)%60)f(2))%10(所有数学运算都完成%10)。

这可以通过简单地对包含f(0)到f(59)最后一位的60个字符的预生成数组进行索引,然后按(n%60)对数组进行索引来进一步加快。如果生成数组所需的时间被计算为计算时间的一部分,那么一次性矩阵计算(最多6个循环)应该更快。

matix可以反转并用于计算负fibonacci值,这些值具有相同的幅度,但具有交替符号:

         |  0  1  |
a^(-1) = |  1 -1  |
f(-6) = -8
f(-5) =  5
f(-4) = -3
f(-3) =  2
f(-2) = -1
f(-1) =  1
f( 0) =  0
f( 1) =  1
f( 2) =  1
f( 3) =  2
f( 4) =  3
f( 5) =  5
f( 6) =  8

如果没有模10,则最大的32位无符号值为f(47)=2971215073,最大的64位无符号数值为f(93)=12200160415121876738。

如果您只需要最后一个数字,有一种更快的方法,就像您的示例输出一样。由于我们看到的是最后一个数字,在我们开始重复之前,可能性是有限的。如果我们取f(1)=1和f(2)=1,那么注意f(61)=1和f(62)=1是第一个重复对。换句话说,斐波那契数的最后一个数字是一个长度为60的循环。计算前60位数字并将其存储在一个数组中,然后返回数组的n mod 60元素。恒定时间。

这里有两个问题。
  1. 递归太慢了。再慢不过了。使用迭代算法或更快的算法。例如,你不能使用Binet算法,它一步到位,因为它会为n=70007产生FP无穷大
  2. 第70007斐波那契数的整数(或长)溢出。您需要使用迭代算法,但每次只记住最后一个数字。最后两个斐波那契数的最后一位数字之和,取10,仍然会给出下一个斐波纳契数的最终数字

只需直接计算Fib数。我记得,确切的公式可以通过使用楼层函数来简化,但我让你来研究这些问题。总结:直接公式很好。

#include <stdio.h>
#include <stdlib.h>
/*
 * By Nedal Kouissi
 * Fibonacci
 * The Rfibonacci means that function use a recursive methode
 * the Ifibonacci means that function use an iteration methode
 */
// finction prototype
unsigned long long int Ifibonacci( unsigned int ); 
// function prototype
unsigned long long int Rfibonacci( unsigned int );
int main(int argc, char** argv) {
    unsigned int f = 1000000000000;
    // display the results
    printf( "Fibonacci( %u ) = %llun", f, Ifibonacci( f ) );
    return (EXIT_SUCCESS);
}
unsigned long long int Ifibonacci( unsigned int x ) {
    if ( x == 0 || x == 1 )
        return x;
    unsigned int i;
    int prevP = 0;
    int prev = 1;
    int result;
    for ( i = 2; i <= x ; ++i ) {
        result = prevP + prev;
        prevP = prev;
        prev = result;
    } // end for
    return result;
} // end function Ifibonacci
unsigned long long int Rfibonacci( unsigned int x ) {
    if ( x == 0 || x == 1 )
        return x;
    else // recursive step
        return Rfibonacci( x - 1 ) + Rfibonacci( x - 2 );
} // end function Rfibonacci