找到适合 int 的最大斐波那契数的最快方法是什么?

What is the fastest method to find the largest Fibonacci-Number that fits in an int?

我承认这个问题有点学术。但是,我相信该解决方案显示了对 (C++) 数字的一些洞察力。

请注意,第 N 个斐波那契数可以使用

递归计算
int Fibonacci(int N)
{
    if (N==1 || N==2) {
        return 1;
    }
    return Fibonacci(N-1) + Fibonacci(N-2);
}

对于这个问题,上面的暴力破解方法不是答案。这是因为 第 N 个斐波那契数可以非递归计算:

long int Fibonacci(int N)
{
    double num1 = pow((1+sqrt(5))/2.0,N);
    double num2 = pow((1-sqrt(5))/2.0,N);

    return (num1-num2)/sqrt(5);
}

方法一(不是最快的):

使用非递归方法计算第N个斐波那契数 可以使用以下代码找到适合 int 的最大斐波那契数:

#include <iostream>
#include <limits.h>
#include <math.h>
#include <chrono>

long int Fibonacci(int n)
{
    double num1 = pow((1+sqrt(5))/2.0,n);
    double num2 = pow((1-sqrt(5))/2.0,n);

    return (num1-num2)/sqrt(5);
}
 
int main()
{
    auto start = std::chrono::system_clock::now();

    int IndexMax = 1;
    while (Fibonacci(IndexMax)<INT_MAX) 
    {
        ++IndexMax;
    }
    --IndexMax;
    auto end = std::chrono::system_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    std::cout << "IndexMax = " << IndexMax << std::endl;
    std::cout << "Fibonacci_two(IndexMax): " << Fibonacci(IndexMax) << std::endl;
    std::cout << "calculation time: " << elapsed.count() << " microseconds" << std::endl;
}

您可以run the code for method 1 online看到以下输出:

IndexMax = 46
Fibonacci_two(IndexMax): 1836311903
calculation time: 33 microseconds

但是还有一个更快的方法:

方法二:

根据Wikipedia,可以反转第 N 个斐波那契数的显式公式。有了这个技巧,我们可以实现一个更快的方法:

#include <iostream>
#include <limits.h>
#include <math.h>
#include <chrono>

long int Fibonacci(int n)
{
    double num1 = pow((1+sqrt(5))/2.0,n);
    double num2 = pow((1-sqrt(5))/2.0,n);

    return (num1-num2)/sqrt(5);
}

double Fibonacci_invert(double Fn)
{
    double num1 = Fn*sqrt(5.0);
    double num2 = sqrt(5.0*Fn*Fn+4.0);
    double phi = (1.0 + sqrt(5.0))/2.0;

    return round(log((num1+num2)/2.0)/log(phi));
}

int main()
{
    auto start = std::chrono::system_clock::now();

    int IndexMax = Fibonacci_invert(INT_MAX);
    int FibonacciMax = Fibonacci(IndexMax);

    auto end = std::chrono::system_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    std::cout << "IndexMax: " << IndexMax << std::endl;
    std::cout << "FibonacciMax: " << FibonacciMax << std::endl;
    std::cout << "calculation time: " << elapsed.count() << " microseconds" << std::endl;
}

感谢 Eric Postpischil 请注意,Fibonacci_Invert 通常不是用于查找不大于其自变量的最大斐波那契数的正确函数。

您可以run the code for method 2 online看到以下输出:

IndexMax: 46
FibonacciMax: 1836311903
calculation time: 23 microseconds

我复制了您的第一个示例并加入了一个我用过很多次的函数。它使用数据而不是指令,使用简单的查找而不是计算。它具有适合 64 位整数的硬编码 table 斐波那契值。当然,如果只需要 32 位值,table 可以做得更小。

#include <iostream>
#include <limits.h>
#include <math.h>
#include <chrono>

long int Fibonacci(int n)
{
    static const long int seq[] = {
        0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,
        987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025,
        121393, 196418, 317811, 514229, 832040, 1346269, 2178309,
        3524578, 5702887, 9227465, 14930352, 24157817, 39088169,
        63245986, 102334155, 165580141, 267914296, 433494437, 701408733,
        1134903170, 1836311903, 2971215073, 4807526976, 7778742049,
        12586269025, 20365011074, 32951280099, 53316291173, 86267571272,
        139583862445, 225851433717, 365435296162, 591286729879,
        956722026041, 1548008755920, 2504730781961, 4052739537881,
        6557470319842, 10610209857723, 17167680177565, 27777890035288,
        44945570212853, 72723460248141, 117669030460994,
        190392490709135, 308061521170129, 498454011879264,
        806515533049393, 1304969544928657, 2111485077978050,
        3416454622906707, 5527939700884757, 8944394323791464,
        14472334024676221, 23416728348467685, 37889062373143906,
        61305790721611591, 99194853094755497, 160500643816367088,
        259695496911122585, 420196140727489673, 679891637638612258,
        1100087778366101931, 1779979416004714189, 2880067194370816120,
        4660046610375530309, 7540113804746346429
    };
    return n < int(sizeof seq / sizeof seq[0]) ? seq[n] : -1;
}

int main()
{
    auto start = std::chrono::system_clock::now();

    int IndexMax = 1;
    while (Fibonacci(IndexMax)<INT_MAX) 
    {
        ++IndexMax;
    }
    --IndexMax;
    auto end = std::chrono::system_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

    std::cout << "IndexMax = " << IndexMax << std::endl;
    std::cout << "Fibonacci_two(IndexMax): " << Fibonacci(IndexMax) << std::endl;
    std::cout << "calculation time: " << elapsed.count() << " microseconds" << std::endl;
}

这是 Compiler Explorer 输出:

IndexMax = 46

Fibonacci_two(IndexMax): 1836311903

calculation time: 0 microseconds

它的速度相当快,我希望它不会违反问题的精神。它没有显示数字见解,但确实说明了代码与数据权衡的有用技术。