斐波那契数

斐波那契数意大利语:Successione di Fibonacci),又译为菲波拿契数菲波那西数斐氏数黄金分割数。所形成的数列称为斐波那契数列意大利语:Successione di Fibonacci),又译为菲波拿契数列菲波那西数列斐氏数列黄金分割数列。这个数列是由意大利数学家斐波那契在他的《算盘书》中提出。

以斐波那契数为边的正方形拼成的近似的黄金矩形(1:1.618)

数学上,斐波那契数是以递归的方法来定义:

用文字来说,就是斐波那契数列由0和1开始,之后的斐波那契数就是由之前的两数相加而得出。首几个斐波那契数是:

1123581321345589144233377610、 987……(OEIS数列A000045

特别指出0不是第一项,而是第零项。

起源

公元1150年印度数学家Gopala金月在研究箱子包装对象长宽刚好为1和2的可行方法数目时,首先描述这个数列。在西方,最先研究这个数列的人是比萨的列奥那多(意大利人斐波那契Leonardo Fibonacci, 1175-1250),他描述兔子生长的数目时用上了这数列:

 
兔子对的数量就是斐波那契数列
  • 第一个月初有一对刚诞生的兔子
  • 第二个月之后(第三个月初)它们可以生育
  • 每月每对可生育的兔子会诞生下一对新兔子
  • 兔子永不死去

假设在 月有兔子总共 对, 月总共有 对。在 月必定总共有 对:因为在 月的时候,前一月( 月)的 对兔子可以存留至第 月(在当月属于新诞生的兔子尚不能生育)。而新生育出的兔子对数等于所有在 月就已存在的 

 
斐波纳契数是帕斯卡三角形的每一条红色对角线上数字的和。

斐波纳契数也是杨辉三角的每一条红色对角线上数字的和。

表达式

为求得斐波那契数列的一般表达式,可以借助线性代数的方法。高中的初等数学知识也能求出。

初等代数解法

已知

  •  
  •  
  •  (n≥3)

首先构建等比数列

 
化简得
 
比较系数可得:
 
不妨设 
解得:

 
又因为有 , 即 为等比数列。

求出数列 

由以上可得:
 

变形得:  。 令 

求数列 进而得到 

 
 ,解得 。 故数列 为等比数列
 。而 , 故有 
又有  
可得 

得出 表达式

 

用数学归纳法证明表达式

证明 ,其中 黄金比例  为任意整数
  •  为非负整数
 时, ,成立
 时, ,成立
设当  时皆成立,即  
 
 
亦成立
  •  为非正整数
 时,成立
 时, ,成立
设当  时皆成立,即  
 
 
亦成立

因此,根据数学归纳法原理,此表达式对于任意整数 皆成立

线性代数解法

 

 

构建一个矩阵方程

 为第 个月有生育能力的兔子数量, 为这一月份的兔子数量。

 

上式表达了两个月之间,兔子数目之间的关系。而要求的是, 的表达式。

求矩阵的特征值 

根据特征值的计算公式,我们需要算出来   所对应的解。

展开行列式有: 

故当行列式的值为 0,解得   

特征向量

将两个特征值代入

 


求特征向量 

 = 

 = 

分解首向量

第一个月的情况是兔子一对,新生0对。

 

将它分解为用特征向量表示。

  (4)

数学归纳法证明

 = 

可得到

  (5)

化简矩阵方程

将(4) 代入 (5)

 

根据3

 

求A的表达式

现在在6的基础上,可以很快求出 的表达式,将两个特征值代入6中

 
 
 (7)

(7)即为 的表达式

数论解法

实际上,如果将斐波那契数列的通项公式写成 ,即可利用解二阶线性齐次递推关系式的方法,写出其特征多项式 (该式和表达斐波那契数列的矩阵的特征多项式一致),然后解出 =  = ,即有 ,其中 为常数。我们知道 ,因此 ,解得 

组合数解法

 [1]

 

黄金比例恒等式解法

 黄金比例 ,则有恒等式  ,其中 为任意整数[注 1],则

 

因此得到 的一般式:

 

此一般式对任意整数 成立

近似值

 为足够大的正整数时,则

 
 

用计算机求解

可通过编程观察斐波那契数列。分为两类问题,一种已知数列中的某一项,求序数。第二种是已知序数,求该项的值。

可通过递归递推的算法解决此两个问题。 事实上当 相当巨大的时候,O(n)的递推/递归非常慢……这时候要用到矩阵快速幂这一技巧,可以使递归加速到O(logn)。

和黄金分割的关系

开普勒发现数列前、后两项之比 ,也组成了一个数列,会趋近黄金分割

 

斐波那契数亦可以用连分数来表示:

 

 

而黄金分割数亦可以用无限连分数表示:

 

而黄金分割数也可以用无限多重根号表示:

 

和自然的关系

 
春黄菊头状花序上,小花呈螺旋状排列,从不同方向可以数出21(深蓝)和13(浅蓝)条旋臂,为相邻的斐氏数。类似的螺旋状排列见于多种植物。

斐氏数列见于不同的生物学现象[2],如树的分枝、叶在枝条上的排列英语Phyllotaxis、菠萝聚花果上小单果的排列、[3]雅枝竹的花蕾、正在舒展的蕨叶、松球的鳞的排列[4]、蜜蜂的家族树[5][6]开普勒曾指出斐氏数列存在于自然界,并以此解释某些花的五边形形态(与黄金分割率相关)。[7]法国菊的“瓣”(舌状花)数通常为斐氏数。[8]1830年,K. F. Schimper和A. Braun发现植物的旋生叶序中,连续两块叶之间转过的角度与周角之比,约成整数比时,常出现斐氏数[9],如  [10]

恒等式

资料来源:[11]

证明以下的恒等式有很多方法。以下会用组合论述来证明。

  •  可以表示用多个1和多个2相加令其和等于 的方法的数目。

不失一般性,我们假设  是计算了将1和2加到n的方法的数目。若第一个被加数是1,有 种方法来完成对 的计算;若第一个被加数是2,有 来完成对 的计算。因此,共有 种方法来计算n的值。

  •  

计算用多个1和多个2相加令其和等于 的方法的数目,同时至少一个加数是2的情况。

如前所述,当 ,有 种这样的方法。因为当中只有一种方法不用使用2,就即  ( 项),于是我们从 减去1。

  1. 若第1个被加数是2,有 种方法来计算加至 的方法的数目;
  2. 若第2个被加数是2、第1个被加数是1,有 种方法来计算加至 的方法的数目。
  3. 重复以上动作。
  4. 若第 个被加数为2,它之前的被加数均为1,就有 种方法来计算加至0的数目。

若该数式包含2为被加数,2的首次出现位置必然在第1和 的被加数之间。2在不同位置的情况都考虑到后,得出 为要求的数目。

  •  
  •  
  •  
  •  
  •  ,其中  的序数皆不限于正整数。[注 2]
    • 特别地,当 时, 
      • 更特别地,当  时,对于数列连续三项,有 
    • 另一方面,当 时,对于数列连续四项,有 [注 3]
  •   ,其中 黄金比例  为任意整数[注 1]
借由上述公式,又可推得以下恒等式[注 4]
    •  [11]
    •  [11]

      特别地,当 时, 

数论性质

公约数和整除关系

  •  整除 ,当且仅当 整除 ,其中 
  •  
  • 任意连续三个菲波那契数两两互素,亦即,对于每一个 
 

斐波那契素数

在斐波那契数列中,有素数[12] 2, 3, 5, 13, 89, 233, 1597, 28657, 514229, 433494437, 2971215073, 99194853094755497, 1066340417491710595814572169, 19134702400093278081449423917……

截至2015年,已知最大的斐波那契素数是第104911个斐波那契数,一共有21925个十进制位。不过,人们仍不知道是不是有无限个斐波那契素数。[13]

§ 公约数和整除关系所述, 总能被 整除,故除 之外,任何斐氏素数的下标必同为素数。由于存在任意长英语Arbitrarily large的一列连续合数,斐氏数列中亦能找到连续任意多项全为合数。

大于 的斐氏数,必不等于素数加一或减一。[14]

与其他数列的交集

斐波那契数列中,只有3个平方数01144[15][16]2001年,派特·奥蒂洛匈牙利语Pethő Attila证明衹有有限多个斐氏数是完全幂。[17]2006年,Y. Bugeaud、M. Mignotte、S. Siksek三人证明此种幂仅得0、1、8、144。[18]

1、3、21、55为仅有的斐氏三角形数Vern Hoggatt英语Verner Emil Hoggatt Jr.曾猜想此结论,后来由罗明证明。[19]

斐波那契数不能为完全数[20]推而广之,除1之外,其他斐氏数皆非多重完全数[21],任两个斐氏数之比亦不能是完全数[22]

n的周期性

斐波那契数列各项模 的余数构成周期数列英语periodic sequence,其最小正周期称为皮萨诺周期[23],至多为 [24]。皮萨诺周期对不同 值的通项公式仍是未解问题,其中一步需要求出某个整数(同余意义下)或二次有限域元素的乘法阶数英语multiplicative order。不过,对固定的 ,求解模 的皮萨诺周期是周期检测英语cycle detection问题的特例。

推广

斐波那西数列是斐波那西n步数列步数为2的特殊情况,也和卢卡斯数列有关。

和卢卡斯数列的关系

 

反费波那西数列

反费波那西数列的递归公式如下:

 

如果它以1,-1开始,之后的数是:1,-1,2,-3,5,-8, ...

即是 

亦可写成 ,其中 是非负整数。

反费波那西数列两项之间的比会趋近 

证明关系式

证明 ,其中 是非负整数

 表示黄金分割数 ,则有 
 ,因此
 

巴都万数列

费波那西数列可以用一个接一个的正方形来表现,巴都万数列则是用一个接一个的等边三角形来表现,它有 的关系。

佩尔数列

佩尔数列的递归公式为 ,前几项为0,1,2,5,12,29,70,169,408,...

应用

1970年,尤里·马季亚谢维奇指出了偶角标的斐波那契函数

 

正是满足Julia Robison假设的丢番图函数,因而证明了希尔伯特第十问题是不可解的。

计算机科学

 
高为6的斐波那契树。平衡因子以绿色标记,节点的高度则为红色。

最左一条路径上的键值全为斐氏数。

  • 考虑以辗转相除法求两个正整数的最大公约数,分析此算法的运行时间。同等输入规模下,最坏情况(用时最长)发生于输入为两个相邻斐氏数时。[25]
  • 归并排序算法有一多相(polyphase)版本用到斐氏数列,是将未排序的数组分为两份,长度为相邻的斐氏数(因此比值接近黄金比)。《计算机程序设计艺术[页码请求]描述了此种多相合并排序英语polyphase merge sort的实作方法,适用于以磁带机为外存的情况。
  • 斐波那契树是一棵二叉树,其每个节点的左右子树高皆恰好差1。由此,斐氏树为AVL树,且对固定高度而言,是最少节点的AVL树。此类树的节点数可写成斐氏数减1。[26]
  • 某些伪随机数生成器用到斐氏数列。[具体情况如何?]
  • 斐波那契堆是一种数据结构,分析其时间复杂度时会用到斐波那契数。
  • 斐波那契编码是以01字串表示正整数的一种方法,负斐波那契编码英语NegaFibonacci coding与之类似,还可以表示负数。

程序参考

JavaScript迭代

function fib(n) {
    var fib_n = function(curr, next, n) {
        if (n == 0) {
            return curr;
        }
        else {
            return fib_n(next, curr+next, n-1);
        }
    }
    return fib_n(0, 1, n);
}
alert(fib(40));

C语言通项公式

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

int main()
{
    int n;
    double constant_a = (1 + sqrt(5)) / 2;
    double constant_b = (1 - sqrt(5)) / 2;
    double constant_c = sqrt(5) / 5;
    double value_1 = 0;
    int value_2 = 0;
    scanf("%d", &n);
    if(n > 0)
    {
        for (int i = 0; i < n; i++)
        {
             value_1 = constant_c * (pow(constant_a, i) - pow(constant_b, i));
             value_2 = (int)value_1;
             printf("%d\n", value_2);
        }
        return 0;
    }
    else
    {
        return -1;
    }
}

c++二变量求某项版

#include <iostream>
using namespace std;
int main () {
	int x,y,n;
    x=1;y=0;
	cin >> n;
	for (int i=0;i<n;i=i+1) {
	    x=x+y;
		y=x-y;
	}
	cout << y;
	return 0;
}

c++通项公式版

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
    unsigned long long n;
    double ca = (1 + sqrt(5)) / 2;
    double cb = (1 - sqrt(5)) / 2;
    double cc = sqrt(5) / 5;
    double v1 = 0;
    double v2 = 0;
    cout <<" ";
    cin>>n;
    if(n > 0)
    {
        for (unsigned long long i = 0; i < n; i++)
    {
            v1 = cc * (pow(ca, i) - pow(cb, i));
        v2 = (int)v1;
        cout <<v2<<endl;
    }
    return 0;
    }
    else
    {
        return -1;
    }
        cout <<'/b';
}

Python语言通项公式

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result
fibs = [0, 1]
numZS = int(input('How many Fibonacci numbers do you want? '))
for i in range(numZS-2):
    fibs.append(fibs[-2] + fibs[-1])
print fibs

Common Lisp

(defun fibs (x)
  (cond ((equal x 0) 1)
        ((equal x 1) 1)
        (t (+ (fibs (- x 1))
              (fibs (- x 2))))))

(defun fibs (x)
  (do ((n 0 (+ n 1))
       (i 1 j)
       (j 1 (+ i j)))
      ((equal n x) i)))

Go

递归版,时间复杂度为 O(2^n):

func fibonacci(n int) int {
	if n < 2 {
		return n
	}

	return fibonacci(n-2) + fibonacci(n-1)
}

通用版,时间复杂度为 O(n):

func fibonacci(n int) int {
	a, b := n%2, 1

	for i := 0; i < n/2; i++ {
		a += b
		b += a
	}

	return a
}

Java语言递归版:

public int fibonacci(int n){
    if(n<2){
     return n;
    }else {
      return fibonacci(n-1)+fibonacci(n-2);
    }
}

Java语言快捷版:

public int fibonacci(int n){
    if(n<2){
     return n;
    }else {
      int[] ans = new int[n];
          ans[0] = 1;
          ans[1] = 2;
          for(int i=2;i<n;i++) {
              ans[i]=ans[i-1]+ans[i-2];
          }
          return ans[n-1];
    }
}

C语言阵列版:

#include <stdio.h>
#include <stdlib.h> 
int main()
{   
     int n,s,L;
     printf("輸入長度");
     scanf("%d",&L);
     while(L<0)
     {
     	printf("錯誤"); 
     	return 0;
	 }
     int a[L]; 
     int x=1,y=2;
     a[0]=x;
     a[1]=x;
     a[2]=y;
	 for(n=3;n<L;n++)
	 {  
		 a[n]=a[n-1]+a[n-2];  	
	 }
       for(n=0;n<L;n++)
     {
         printf("%d ",a[n]);
     }
     system("pause");
     return 0;
}

Python Lambda 递归版:

fib = lambda n: n if n<2 else fib(n-1) + fib(n-2)

延伸阅读