找到适合 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
它的速度相当快,我希望它不会违反问题的精神。它没有显示数字见解,但确实说明了代码与数据权衡的有用技术。
我承认这个问题有点学术。但是,我相信该解决方案显示了对 (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
它的速度相当快,我希望它不会违反问题的精神。它没有显示数字见解,但确实说明了代码与数据权衡的有用技术。