如下图,通常大家都用公式一来计算斐波那契数列的,其实还有通项公式二:一个非常牛叉的内比公式,号称是用无理数表示有理数(且是整数)的典范。
只一行代码能计算数列全部项
预定义两个宏常量,使代码更简洁些:
#include <iostream> #include <iomanip> #include <cmath> using namespace std; #define M_SQRT5 2.2360679774997896964091736687313 #define M_1pSQRT5_2 1.6180339887498948482045868343656 size_t Fibo(size_t n) { return (size_t)round((pow(M_1pSQRT5_2,n)-pow(1-M_1pSQRT5_2,n))/M_SQRT5); } size_t fibo(size_t n) //引入定义式作比较 { size_t f, f1, f2; f = f1 = f2 = 1; for (auto i=3; i<=n; ++i){ f = f1 + f2; if (f<f2){ //设置溢出条件 f=0; break; } f1 = f2; f2 = f; } return f; } int main(void) { for (long n=1;n<=100;n++) cout<<n<<"\t= "<<setprecision(18)<<Fibo(n)<<"\t"<<fibo(n) <<"\t"<<(Fibo(n)==fibo(n)?"True":"False")<<endl; return 0; }
测试结果: 1 = 1 1 True 2 = 1 1 True 3 = 2 2 True 4 = 3 3 True 5 = 5 5 True 6 = 8 8 True 7 = 13 13 True 8 = 21 21 True 9 = 34 34 True 10 = 55 55 True 11 = 89 89 True 12 = 144 144 True 13 = 233 233 True 14 = 377 377 True 15 = 610 610 True 16 = 987 987 True 17 = 1597 1597 True 18 = 2584 2584 True 19 = 4181 4181 True 20 = 6765 6765 True 21 = 10946 10946 True 22 = 17711 17711 True 23 = 28657 28657 True 24 = 46368 46368 True 25 = 75025 75025 True 26 = 121393 121393 True 27 = 196418 196418 True 28 = 317811 317811 True 29 = 514229 514229 True 30 = 832040 832040 True 31 = 1346269 1346269 True 32 = 2178309 2178309 True 33 = 3524578 3524578 True 34 = 5702887 5702887 True 35 = 9227465 9227465 True 36 = 14930352 14930352 True 37 = 24157817 24157817 True 38 = 39088169 39088169 True 39 = 63245986 63245986 True 40 = 102334155 102334155 True 41 = 165580141 165580141 True 42 = 267914296 267914296 True 43 = 433494437 433494437 True 44 = 701408733 701408733 True 45 = 1134903170 1134903170 True 46 = 1836311903 1836311903 True 47 = 2971215073 2971215073 True 48 = 4807526976 4807526976 True 49 = 7778742049 7778742049 True 50 = 12586269025 12586269025 True 51 = 20365011074 20365011074 True 52 = 32951280099 32951280099 True 53 = 53316291173 53316291173 True 54 = 86267571272 86267571272 True 55 = 139583862445 139583862445 True 56 = 225851433717 225851433717 True 57 = 365435296162 365435296162 True 58 = 591286729879 591286729879 True 59 = 956722026041 956722026041 True 60 = 1548008755920 1548008755920 True 61 = 2504730781961 2504730781961 True 62 = 4052739537881 4052739537881 True 63 = 6557470319842 6557470319842 True 64 = 10610209857723 10610209857723 True 65 = 17167680177565 17167680177565 True 66 = 27777890035288 27777890035288 True 67 = 44945570212853 44945570212853 True 68 = 72723460248141 72723460248141 True 69 = 117669030460994 117669030460994 True 70 = 190392490709135 190392490709135 True 71 = 308061521170129 308061521170129 True 72 = 498454011879264 498454011879264 True 73 = 806515533049393 806515533049393 True 74 = 1304969544928657 1304969544928657 True 75 = 2111485077978050 2111485077978050 True 76 = 3416454622906706 3416454622906707 False 77 = 5527939700884755 5527939700884757 False 78 = 8944394323791463 8944394323791464 False 79 = 14472334024676218 14472334024676221 False 80 = 23416728348467676 23416728348467685 False 81 = 37889062373143896 37889062373143906 False 82 = 61305790721611584 61305790721611591 False 83 = 99194853094755488 99194853094755497 False 84 = 160500643816367040 160500643816367088 False 85 = 259695496911122528 259695496911122585 False 86 = 420196140727489600 420196140727489673 False 87 = 679891637638612096 679891637638612258 False 88 = 1100087778366101632 1100087778366101931 False 89 = 1779979416004713728 1779979416004714189 False 90 = 2880067194370815488 2880067194370816120 False 91 = 4660046610375529472 4660046610375530309 False 92 = 7540113804746344448 7540113804746346429 False 93 = 12200160415121872896 12200160415121876738 False 94 = 0 0 True 95 = 0 0 True 96 = 0 0 True 97 = 0 0 True 98 = 0 0 True 99 = 0 0 True 100 = 0 0 True -------------------------------- Process exited after 1.111 seconds with return value 0 请按任意键继续. . .
从运行结果可知:内比公式可以精确计算到第75项,从76项开始long double型的精度不够用了,到94项和递推算法一样溢出。
如不强求返回值一定是整数,可以改成long doubel型函数,一直到1475项溢出;当然只有前75项是精确值,之后的都是约数。
代码修改后,如下:
#include <iostream> #include <iomanip> #include <cmath> using namespace std; #define M_SQRT5 2.2360679774997896964091736687313 #define M_1pSQRT5_2 1.6180339887498948482045868343656 long double Fibo(size_t n) { return round((pow(M_1pSQRT5_2,n)-pow(1-M_1pSQRT5_2,n))/M_SQRT5); } int main(void) { for (long n=1;n<=100;n++) cout<<n<<"\t= "<<setprecision(21)<<Fibo(n)<<endl; cout << "... ..." << endl; for (long n=1470;n<=1480;n++) cout<<n<<"\t= "<<setprecision(21)<<Fibo(n)<<endl; return 0; }
测试结果:
1 = 1
2 = 1
3 = 2
4 = 3
5 = 5
6 = 8
7 = 13
8 = 21
9 = 34
10 = 55
11 = 89
12 = 144
13 = 233
14 = 377
15 = 610
16 = 987
17 = 1597
18 = 2584
19 = 4181
20 = 6765
21 = 10946
22 = 17711
23 = 28657
24 = 46368
25 = 75025
26 = 121393
27 = 196418
28 = 317811
29 = 514229
30 = 832040
31 = 1346269
32 = 2178309
33 = 3524578
34 = 5702887
35 = 9227465
36 = 14930352
37 = 24157817
38 = 39088169
39 = 63245986
40 = 102334155
41 = 165580141
42 = 267914296
43 = 433494437
44 = 701408733
45 = 1134903170
46 = 1836311903
47 = 2971215073
48 = 4807526976
49 = 7778742049
50 = 12586269025
51 = 20365011074
52 = 32951280099
53 = 53316291173
54 = 86267571272
55 = 139583862445
56 = 225851433717
57 = 365435296162
58 = 591286729879
59 = 956722026041
60 = 1548008755920
61 = 2504730781961
62 = 4052739537881
63 = 6557470319842
64 = 10610209857723
65 = 17167680177565
66 = 27777890035288
67 = 44945570212853
68 = 72723460248141
69 = 117669030460994
70 = 190392490709135
71 = 308061521170129
72 = 498454011879264
73 = 806515533049393
74 = 1304969544928657
75 = 2111485077978050
76 = 3416454622906706
77 = 5527939700884755
78 = 8944394323791463
79 = 14472334024676218
80 = 23416728348467676
81 = 37889062373143896
82 = 61305790721611584
83 = 99194853094755488
84 = 160500643816367040
85 = 259695496911122528
86 = 420196140727489600
87 = 679891637638612096
88 = 1100087778366101632
89 = 1779979416004713728
90 = 2880067194370815488
91 = 4660046610375529472
92 = 7540113804746344448
93 = 12200160415121872896
94 = 19740274219868217344
95 = 31940434634990088192
96 = 51680708854858301440
97 = 83621143489848410112
98 = 135301852344706695168
99 = 218922995834555138048
100 = 354224848179261800448
... ...
1470 = 7.28360130920160113816e+306
1471 = 1.17851144787914223854e+307
1472 = 1.90687157879930235235e+307
1473 = 3.08538302667844459089e+307
1474 = 4.99225460547774819064e+307
1475 = inf
1476 = inf
1477 = inf
1478 = inf
1479 = inf
1480 = inf
--------------------------------
Process exited after 1.065 seconds with return value 0
请按任意键继续. . .
long double的精度只够用到73项,但long long的宽度够用到93项,我们可以利用斐波那契数列性质 F(n)=F(n-m)*F(m-1)+F(n-m+1)*F(m) 把用内比公式的函数参数最大值也拉升到93:
#include <string> #include <cmath> #define M_SQRT5 2.2360679774997896964091736687313 #define M_1pSQRT5_2 1.6180339887498948482045868343656 size_t intFib(size_t n) { return n>93?0:(n>75?intFib(n-75)*intFib(74)+intFib(n-74)*intFib(75):(size_t)round((pow(M_1pSQRT5_2,n)-pow(1-M_1pSQRT5_2,n))/M_SQRT5)); } string strFib(size_t n) { return n>93?"":to_string(n>75?intFib(n-75)*intFib(74)+intFib(n-74)*intFib(75):intFib(n)); }