斐波那契数列和矩阵的特征值于特征向量的关系

从事软件开发的人对斐波那契数列可以说在熟悉不过了,一般是学习递归算法的入门案例写在教科书中,它用递推公式表达是这个样子的:

F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)

作为一名体面的码农,看到这个公式不免手痒,必须要安排它一下,就拿相邻项的比值开刀,代码如下:

#include <stdio.h>
#include <stdlib.h>

long long feibonaqie(int n)
{
	if(n == 0)
		return 0;
	if(n == 1)
		return 1;

	return feibonaqie(n-1) + feibonaqie(n-2);
}

int main(void)
{
	int i;
	long long pre, cur;
	double portion;
	
	for(i = 0; i < 100; i ++)
	{
 		pre = cur;
		cur = feibonaqie(i);
 		if(i >= 2)
		{
			portion = (float)cur/(float)pre;
		}

		printf("feibonaqie(%d) = %lld.portion = %f\n", i, cur, portion);
	}

	return 0;
}

例子很简单,程序试图获取斐波那契数列前100项的值,常规的通过递归逻辑获取数列第N项值相信大家都能看懂,略去不讲。这里主要讲添加的一个自定义逻辑,它就是在计算的过程中,我们顺便计算了一下当前项和它前面一项的比值,并打印出来,这一打印,发现了一个奇特的规律:

上面的程序在我的电脑上执行到前50项时,花了半个钟的时间,简直是龟速,照这个速度,有生之年是看不到程序结束的了,不过即便如此,根据前50项的计算结果,貌似符合下面的规律:

\lim_{n\rightarrow \infty }\frac{F(n)}{F(n-1)}=1.618034

该如何证明呢?

数学最令人感到奇妙的是,在看似完全不相关的问题之间,竟然隐藏着自然而又出乎意料的关系,以这个问题为例,这个结论竟然可以通过线性代数中的矩阵特征向量和特征值的概念来解释。

我们先从从直观上解释,为什么这个结果是符合直觉的,然后在进行理论推导。

首先,我们换一种形式来表达上面的递推公式:

由于

F(n)=F(n-1)+F(n-2), F(n-1)=F(n-1)

所以我们可以将递推公式写成矩阵形式:

\begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} F(n-1)\\ F(n-2) \end{bmatrix}

我们仔细观察,看到两边的列向量具有相同的结构,都符合数列相连的前后项形式,既然是直观解释并非理论证明,我们先假设极限

\lim_{n\rightarrow \infty }\frac{F(n)}{F(n-1)}

存在,并且其值为\lambda

所以:

\\ \lim_{n\rightarrow \infty }\frac{F(n)}{F(n-1)}= \lim_{n\rightarrow \infty }\frac{F(n-1)}{F(n-2)}=\lambda

则,矩阵形式可以改写为:

\begin{bmatrix} \lambda F(n-1)\\ F(n-1) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} \lambda F(n-2)\\ F(n-2) \end{bmatrix}=>F(n-1) \begin{bmatrix} \lambda \\ 1 \end{bmatrix}=F(n-2)\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} \lambda \\ 1 \end{bmatrix}

\\F(n-1) \begin{bmatrix} \lambda \\ 1 \end{bmatrix}=F(n-2)\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} \lambda \\ 1 \end{bmatrix}=>\frac{F(n-1)}{F(n-2)}\begin{bmatrix} \lambda \\ 1 \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} \lambda \\ 1 \end{bmatrix}=\\ \lambda\begin{bmatrix} \lambda \\ 1 \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} \lambda \\ 1 \end{bmatrix}

两边取极限,最后等式化为了

\\ \lambda\begin{bmatrix} \lambda \\ 1 \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} \lambda \\ 1 \end{bmatrix}

到了这里,相信你已经想起了什么,没错,这个形式是多么的像矩阵的特征值和特征向量的定义式:

A\vec{x}=\lambda\vec{x}

只要矩阵

\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}

的特征值恰好是特征向量第一个元素和第二个元素的比值,一切就会完美符合!

我们看一下是这样吗?

用octave求得此矩阵的特征向量和特征值:

可以看到,此矩阵有两个特征值,分别为-0.61803和1.61803,它们对应的特征向量分别为:

\begin{bmatrix} 0.52573\\ -0.85065 \end{bmatrix}

\begin{bmatrix} -0.85065\\ -0.52573 \end{bmatrix}

它们恰好满足

0.52573/-0.85065=-0.61803

-0.85065/-0.52573=1.6180

由于斐波那契数列是逐项递增的,所以结果是特征值1.61803对应的特征向量,这也完美符合上面程序的打印,这并不是巧合,冥冥中隐藏了某种奥秘,通过这种方式,我们揭开了它的一角。

如果修改一下极限的定义形式,将极限定义为

\lim_{n\rightarrow \infty }\frac{F(n-1)}{F(n)}

这个时候,就是 -0.61803对应的特征值和特征向量了,所以,1.61803并没有什么特殊的,只是比值的顺序不同而已。

这个证明过程依赖直觉,不够严密,事不宜迟,下面用更加严谨的方式来证明这个结论。

理论证明:

首先计算矩阵A的特征值以及特征值对应的特征向量:

A=\begin{bmatrix} 1& 1\\ 1 & 0 \end{bmatrix}

\left | A-\lambda I \right | = \begin{vmatrix} 1-\lambda& 1\\ 1 & -\lambda \end{vmatrix}=\lambda^2-\lambda-1=0

所以:

\lambda_1=\frac{1-\sqrt{5}}{2}\approx -0.618, \lambda_2=\frac{1+\sqrt{5}}{2}\approx 1.618

\lambda_1对应的特征向量是

\begin{bmatrix} \lambda_1\\ 1 \end{bmatrix}=\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1 \end{bmatrix}\approx \begin{bmatrix} -0.618\\ 1 \end{bmatrix}

\begin{bmatrix} \lambda_2\\ 1 \end{bmatrix}=\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1 \end{bmatrix}\approx \begin{bmatrix} 1.618\\ 1 \end{bmatrix}

根据线性代数理论,属于不同特征值的特征向量线性无关,而线性无关的特征向量的线性组合一定可以表示整个平面,所以,斐波那契数列的初始项一定也可以由这两个特征向量来表示,也就是

\begin{bmatrix} 1\\ 0\end{bmatrix}=c_1\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix}+c_2\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}

求解上面的二元一次方程,得到:

c_1=-\frac{\sqrt{5}}{5},c_2=\frac{\sqrt{5}}{5}

所以,斐波那契数列的递推公式也可以表达为:

\begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}\begin{bmatrix} F(n-1)\\ F(n-2) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^2\begin{bmatrix} F(n-2)\\ F(n-3) \end{bmatrix}=\cdots=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\begin{bmatrix} F(1)\\ F(0) \end{bmatrix}

所以

\begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\begin{bmatrix} F(1)\\ F(0) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\bigg\{c_1\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix}+c_2\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}\bigg\}

 所以:

\\ \begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}=\frac{\sqrt{5}}{5}\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\bigg\{\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}-\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix}\bigg\} \\=\frac{\sqrt{5}}{5}\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}-\frac{\sqrt{5}}{5}\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix}

因为:

A\vec{x}=\lambda\vec{x},A^2\vec{x}=\lambda^2\vec{x},\cdots, A^n\vec{x}=\lambda^n\vec{x}

所以:

\\ \begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}=\frac{\sqrt{5}}{5}\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}-\frac{\sqrt{5}}{5}\begin{bmatrix} 1 & 1\\ 1& 0 \end{bmatrix}^{n-1}\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix} = \\\frac{\sqrt{5}}{5}\lambda^{n-1}_2\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}-\frac{\sqrt{5}}{5}\lambda^{n-1}_1\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix}=\frac{\sqrt{5}}{5}{(\frac{1+\sqrt{5}}{2})}^{n-1}\begin{bmatrix} \frac{1+\sqrt{5}}{2}\\ 1\end{bmatrix}-\frac{\sqrt{5}}{5}{(\frac{1-\sqrt{5}}{2})}^{n-1}\begin{bmatrix} \frac{1-\sqrt{5}}{2}\\ 1\end{bmatrix}

所以,通过求解矩阵的特征值和特征向量,我们竟然得到了斐波那契数列的通项公式!

F(n)=\frac{\sqrt{5}}{5}{(\frac{1+\sqrt{5}}{2})}^{n-1}\frac{1+\sqrt{5}}{2}-\frac{\sqrt{5}}{5}{(\frac{1-\sqrt{5}}{2})}^{n-1}\frac{1-\sqrt{5}}{2}

化简后得到通项公式:

F(n)=\frac{\sqrt{5}}{5}\bigg[{(\frac{1+\sqrt{5}}{2})}^{n}-{(\frac{1-\sqrt{5}}{2})}^{n}\bigg]

真是大大的惊喜,大大的意外!

而且,关于为何初始向量

\begin{bmatrix} 1\\ 0\end{bmatrix}

不在特征向量的方向上,仍然最后收敛于特征向量,也得到了解释,通过通项公式可以看出,随着n的增大,

{(\frac{1-\sqrt{5}}{2})}^{n}

所代表的项目由于特征值小于1,会逐渐趋近于0,只剩下特征值1.618对应的特征向量,所以最后显露出来的,是特征值\lambda_2代表的特征,\lambda_1的特征会逐渐消失。

在控制科学领域,\lambda_2为对应稳态分量,\lambda_1对应暂态分量,随着次数逐渐升高,\lambda_1对应项逐渐收敛为0,仅仅剩下稳态分量和稳态分量对应的稳态向量,这也是上面的推导过程证明的结论。

从上面的理论推导结果我们还可以得到一个推论,就是斐波那契数列的相邻项比值的极限,和初始向量的定义无关,比如,我们随便修改一下初始条件为:

\begin{bmatrix} F(1)\\ F(0)\end{bmatrix}=\begin{bmatrix} 8\\ 9\end{bmatrix}

计算最终极限仍然是1.618034

斐波那契数列,竟然通过相邻项求比值的方式,和矩阵的特征值和特征向量建立了联系,让人不得惊叹于数学的奇妙。

斐波那契数列将遵循这个趋势,这个趋势就是当前项是前一项的1.61804倍,随着N的增加,这个比例会越来越精确,F(n),F(n-1)构成的列向量会越来越接近1.61804对应的特征向量,我们可以通过这种方式来计算下一位的值,毕竟收限于算力,对于普通的PC来说,想要计算斐波那契数列的前100项的值,也是难如登天的一件事情。

写这篇文章花了1个小时,在这1个小时的时间里,程序又算出了5项数列的值

这是运行一夜的情况,四核八线程I5,一个晚上仅仅算出来56,57,58,59四项的值。

既然已经找到了通项公式,接下来我们用通项公式来计算斐波那契数列前100项的值,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

unsigned long long febnaqi(int n)
{
	double sqrt5=sqrt(5.00);
	double vec1 = (1 + sqrt5)/2;
	double vec2 = (1 - sqrt5)/2;

	return (sqrt5/5) * (pow(vec1, n)-pow(vec2,n));
}

int main(void)
{
	int i;
	
	for(i = 0; i < 100; i ++)
	{
		printf("febnaqi(%d)=%llu.\n", i, febnaqi(i));
	}

	return 0;
}

运行结果如下,最后94-99已经溢出,无法的到正确的值,从程序开始运行到执行结束,也就一眨眼的事,可以看到,我们推导除了斐波那契数列的通项公式后,大大加速了我们的计算效率,这也是为什么好的算法如此重要的原因。

czl@czl-VirtualBox:~/WorkSpace$ ./a.out 
febnaqi(0)=0.
febnaqi(1)=1.
febnaqi(2)=1.
febnaqi(3)=2.
febnaqi(4)=3.
febnaqi(5)=5.
febnaqi(6)=8.
febnaqi(7)=13.
febnaqi(8)=21.
febnaqi(9)=34.
febnaqi(10)=55.
febnaqi(11)=89.
febnaqi(12)=144.
febnaqi(13)=233.
febnaqi(14)=377.
febnaqi(15)=610.
febnaqi(16)=987.
febnaqi(17)=1597.
febnaqi(18)=2584.
febnaqi(19)=4181.
febnaqi(20)=6765.
febnaqi(21)=10946.
febnaqi(22)=17711.
febnaqi(23)=28657.
febnaqi(24)=46368.
febnaqi(25)=75025.
febnaqi(26)=121393.
febnaqi(27)=196418.
febnaqi(28)=317811.
febnaqi(29)=514229.
febnaqi(30)=832040.
febnaqi(31)=1346269.
febnaqi(32)=2178309.
febnaqi(33)=3524578.
febnaqi(34)=5702887.
febnaqi(35)=9227465.
febnaqi(36)=14930352.
febnaqi(37)=24157817.
febnaqi(38)=39088169.
febnaqi(39)=63245986.
febnaqi(40)=102334155.
febnaqi(41)=165580141.
febnaqi(42)=267914296.
febnaqi(43)=433494437.
febnaqi(44)=701408733.
febnaqi(45)=1134903170.
febnaqi(46)=1836311903.
febnaqi(47)=2971215073.
febnaqi(48)=4807526976.
febnaqi(49)=7778742049.
febnaqi(50)=12586269025.
febnaqi(51)=20365011074.
febnaqi(52)=32951280099.
febnaqi(53)=53316291173.
febnaqi(54)=86267571272.
febnaqi(55)=139583862445.
febnaqi(56)=225851433717.
febnaqi(57)=365435296162.
febnaqi(58)=591286729879.
febnaqi(59)=956722026041.
febnaqi(60)=1548008755920.
febnaqi(61)=2504730781961.
febnaqi(62)=4052739537881.
febnaqi(63)=6557470319842.
febnaqi(64)=10610209857723.
febnaqi(65)=17167680177565.
febnaqi(66)=27777890035288.
febnaqi(67)=44945570212853.
febnaqi(68)=72723460248141.
febnaqi(69)=117669030460994.
febnaqi(70)=190392490709135.
febnaqi(71)=308061521170129.
febnaqi(72)=498454011879265.
febnaqi(73)=806515533049395.
febnaqi(74)=1304969544928660.
febnaqi(75)=2111485077978055.
febnaqi(76)=3416454622906716.
febnaqi(77)=5527939700884771.
febnaqi(78)=8944394323791489.
febnaqi(79)=14472334024676262.
febnaqi(80)=23416728348467748.
febnaqi(81)=37889062373144008.
febnaqi(82)=61305790721611760.
febnaqi(83)=99194853094755776.
febnaqi(84)=160500643816367552.
febnaqi(85)=259695496911123360.
febnaqi(86)=420196140727490944.
febnaqi(87)=679891637638614400.
febnaqi(88)=1100087778366105216.
febnaqi(89)=1779979416004719616.
febnaqi(90)=2880067194370825216.
febnaqi(91)=4660046610375545856.
febnaqi(92)=7540113804746370048.
febnaqi(93)=12200160415121915904.
febnaqi(94)=0.
febnaqi(95)=0.
febnaqi(96)=0.
febnaqi(97)=0.
febnaqi(98)=0.
febnaqi(99)=0.
czl@czl-VirtualBox:~/WorkSpace$

初始的程序版本使用的是尾递归的形式,尾递归是指在最后一行的递归调用,并且递归调用语句只有一个,由于是最后一行的调用,这时候的栈帧临时存储不具有保存价值,所以,除了形式上的简明之外,递归失去了意义,这种结构的递归不需要使用栈即可用迭代法或者辗转法消除,并且斐波那契数列并不适合使用递归方法,后面会解释。

辗转法消除递归的程序版本:

另一个用空间换时间策略的实现版本,由于使用了数组预分配空间,不需要辗转赋值:

运行结果:

图形化表述:

我们用geogebra工具图形化表述上述过程,红色的向量是\lambda_2对应的特征向量,而黑色的向量则是斐波那契数列的初始条件向量,随着N的递增,经过变换后的向量最终越来越趋近于特征向量的方向,这就是上述过程的图形化表述。

总结:

  • 理论推导的关键一步,是将初始向量表示为特征向量的线性组合,突破这一步,推导过程豁然开朗,通项公式也就水到渠成了。
  • 特征值是反映变化速度的量,反映了在多个变化因素里,谁占主导地位,谁决定了变化的速度,特征向量是反映稳定性的量,决定了变化的宿命,即决定了它最终向谁收敛,所以我们看到了程序运行结果逐渐向着极限值逼近。
  • 当编写递归程序的使用,必须满足以下几个条件
    1. 基准情形,必须有某些基准情形,在基准情形下,不用递归就能求解,如果忘记了基准情形,递归就会失控。
    2. 不断推进,对于那些需要递归求解的情形,递归调用必须朝着产生基准情形的方向前进
    3. 所有的递归调用都能运行
    4. 合成效益法则,在求解一个问题的同一个实例时,切勿在不同的递归调用中做重复性工作,这条法则说明,使用递归来计算斐波那契数列不是一个好办法,因为其中存在这很多的重复计算,以F(n)=F(n-1)+F(n-2)为例,当计算F(n-1)时用到的F(n-2),后面还要重复计算一次。

结束!

Guess you like

Origin blog.csdn.net/tugouxp/article/details/120660974