Fibonacci数列

F i b o n a c c i Fibonacci Fibonacci 数列: F 0 = 0 , F 1 = 1 , F n = F n − 1 + F n − 2 ( n ≥ 2 ) F_0=0,F_1=1,F_n=F_{n-1}+F_{n-2}(n\ge 2) F0=0,F1=1,Fn=Fn1+Fn2(n2)​​​ .

本文重点关注 F i b o n a c c i Fibonacci Fibonacci 数列的通项公式与第 n n n 项的计算.

一、通项公式

构造矩阵递推式:
{ F n + 1 = F n + F n − 1 , F n = F n + 0 ⋅ F n − 1 . \begin{cases} F_{n+1}=F_n+F_{n-1},\\ F_{n}=F_n+0\cdot F_{n-1}. \end{cases} {Fn+1=Fn+Fn1,Fn=Fn+0Fn1.

⇒ ( F n + 1 F n ) = ( 1 1 1 0 ) ( F n F n − 1 ) = ( 1 1 1 0 ) 2 ( F n − 1 F n − 2 ) = ⋯ = ( 1 1 1 0 ) n ( F 1 F 0 ) . \begin{aligned} \Rightarrow \begin{pmatrix} F_{n+1} \\ F_{n} \end{pmatrix} &=\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}\begin{pmatrix} F_{n} \\ F_{n-1} \end{pmatrix}\\ &=\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^{2}\begin{pmatrix} F_{n-1} \\ F_{n-2} \end{pmatrix}\\ &=\cdots \\ &=\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^{n}\begin{pmatrix} F_{1} \\ F_{0} \end{pmatrix}. \end{aligned} (Fn+1Fn)=(1110)(FnFn1)=(1110)2(Fn1Fn2)==(1110)n(F1F0).

A = ( 1 1 1 0 ) A=\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} A=(1110) A A A 为实对称矩阵,因此必定存在可逆矩阵 P P P​ ,使 P − 1 A P = Λ P^{-1}AP=\Lambda P1AP=Λ .

P = ( − 2 2 5 + 1 5 − 1 ) P=\begin{pmatrix} -2 & 2 \\ \sqrt{5}+1 & \sqrt{5}-1 \end{pmatrix} P=(25 +125 1)​​ ,则

P − 1 = ( 1 10 + 2 5 1 10 − 2 5 ) ( − 2 5 + 1 2 5 − 1 ) P^{-1}=\begin{pmatrix} \frac{1}{10+2\sqrt{5}} & \\ & \frac{1}{10-2\sqrt{5}} \end{pmatrix}\begin{pmatrix} -2 & \sqrt{5}+1 \\ 2 & \sqrt{5}-1 \end{pmatrix} P1=(10+25 11025 1)(225 +15 1)​​​ ,

满足 P − 1 A P = Λ = ( 1 − 5 2 1 + 5 2 ) P^{-1}AP=\Lambda=\begin{pmatrix} \dfrac{1-\sqrt{5}}{2} & \\ & \dfrac{1+\sqrt{5}}{2} \end{pmatrix} P1AP=Λ=215 21+5 ​ ​.

于是
⇒ ( F n + 1 F n ) = A n ( F 1 F 0 ) = P Λ n P − 1 ( 1 0 ) = ( − 1 5 ( 1 − 5 2 ) n + 1 + 1 5 ( 1 + 5 2 ) n + 1 − 1 5 ( 1 − 5 2 ) n + 1 5 ( 1 + 5 2 ) n ) . \begin{aligned} \Rightarrow \begin{pmatrix} F_{n+1} \\ F_{n} \end{pmatrix} &=A^{n}\begin{pmatrix} F_{1} \\ F_{0} \end{pmatrix}\\ &=P\Lambda ^{n}P^{-1}\begin{pmatrix} 1 \\ 0 \end{pmatrix}\\ &=\begin{pmatrix} \dfrac{-1}{\sqrt{5}}\left( \dfrac{1-\sqrt{5}}{2}\right) ^{n+1} +\dfrac{1}{\sqrt{5}}\left( \dfrac{1+\sqrt{5}}{2}\right) ^{n+1} \\ \dfrac{-1}{\sqrt{5}}\left( \dfrac{1-\sqrt{5}}{2}\right) ^{n} +\dfrac{1}{\sqrt{5}}\left( \dfrac{1+\sqrt{5}}{2}\right) ^{n} \end{pmatrix}. \end{aligned} (Fn+1Fn)=An(F1F0)=PΛnP1(10)=5 1(215 )n+1+5 1(21+5 )n+15 1(215 )n+5 1(21+5 )n.
F i b o n a c c i Fibonacci Fibonacci 数列的通项公式为
F n = 1 5 ( 1 + 5 2 ) n − 1 5 ( 1 − 5 2 ) n . ( n ≥ 0 ) F_n=\dfrac{1}{\sqrt{5}}\left( \dfrac{1+\sqrt{5}}{2}\right) ^{n}-\dfrac{1}{\sqrt{5}}\left( \dfrac{1-\sqrt{5}}{2}\right) ^{n}.(n\ge 0) Fn=5 1(21+5 )n5 1(215 )n.(n0)
由于
∣ F n − 1 5 ( 1 + 5 2 ) n ∣ = 1 5 ( 5 − 1 2 ) n ≤ 1 5 < 1 2 . ( n ≥ 0 ) \left| F_{n}-\dfrac{1}{\sqrt{5}}\left( \dfrac{1+\sqrt{5}}{2}\right) ^{n}\right| =\dfrac{1}{\sqrt{5}}\left( \dfrac{\sqrt{5}-1}{2}\right) ^{n}\le \dfrac{1}{\sqrt{5}} \lt\dfrac 12.(n\ge 0) Fn5 1(21+5 )n=5 1(25 1)n5 1<21.(n0)
因此
F n = ⌊ 1 5 ( 5 + 1 2 ) n + 1 2 ⌋ . ( n ≥ 0 ) F_{n}=\left\lfloor \dfrac{1}{\sqrt{5}}\left( \dfrac{\sqrt{5}+1}{2}\right) ^{n}+\dfrac{1}{2}\right\rfloor.(n\ge 0) Fn=5 1(25 +1)n+21.(n0)

二、计算

方法一:利用递推公式

{ F n = F n − 1 + F n − 2 , n ≥ 2 , F 0 = 0 , F 1 = 1. \begin{cases}F_{n}=F_{n-1}+F_{n-2},n\geq 2,\\ F_{0}=0,F_{1}=1.\end{cases} {Fn=Fn1+Fn2,n2,F0=0,F1=1.

时间复杂度 O ( n ) O(n) O(n) .

def get_fib1(n: int):
    """递推式求Fibonacci第n项"""
    if n < 0:
        return None
    if n == 0 or n == 1:
        return n
    a, b = 0, 1
    for i in range(2, n + 1):
        a += b
        a, b = b, a
    return b

方法二:矩阵快速幂

A = ( 1 1 1 0 ) A=\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} A=(1110) ,则 ( F n + 1 F n ) = A n ( 1 0 ) \begin{pmatrix} F_{n+1} \\ F_{n} \end{pmatrix}=A^{n}\begin{pmatrix} 1 \\ 0 \end{pmatrix} (Fn+1Fn)=An(10) .

显然 F n = A 2 , 1 n F_n=A^n_{2,1} Fn=A2,1n​ .

时间复杂度 O ( log ⁡ 2 n ) O(\log_2n) O(log2n)​ .

F 47 F_{47} F47 超过 4 4 4 字节整数范围导致结果溢出.

def get_fib2(n: int):
    """矩阵快速幂计算F_n
        n=47时溢出
    """
    if n < 0:
        return None
    import numpy as np
    tmp = [[1, 0], [0, 1]]
    a = [[1, 1], [1, 0]]
    while n > 0:
        if n & 1:
            tmp = np.dot(tmp, a)
        a = np.dot(a, a)
        n >>= 1
    return tmp[1][0]

方法三:通项公式计算

通项公式:
F n = ⌊ 1 5 ( 5 + 1 2 ) n + 1 2 ⌋ . F_{n}=\left\lfloor \dfrac{1}{\sqrt{5}}\left( \dfrac{\sqrt{5}+1}{2}\right) ^{n}+\dfrac{1}{2}\right\rfloor. Fn=5 1(25 +1)n+21.
时间复杂度取决于计算 ((1 + sqrt5) / 2) ** n 的速度.

n = 71 n=71 n=71​ 时会由于浮点误差过大导致结果不对.

def get_fib3(n: int):
    """利用通项公式求F_n
        n=71时浮点误差过大
    """
    if n < 0:
        return None
    import math
    sqrt5 = math.sqrt(5)
    return int(1 / sqrt5 * ((1 + sqrt5) / 2) ** n + 0.5)

使用高精度可以在一定程度上解决浮点误差问题.

若运算精度取 28 28 28​ , n = 123 n=123 n=123​​ 时结果错误.

若运算精度取 100 100 100​ , n = 464 n=464 n=464​ 时结果错误.

若运算精度取 1000 1000 1000​ , n = 4768 n=4768 n=4768​ 时结果错误.

def get_fib4(n: int):
    """利用通项公式求F_n"""
    import decimal
    from decimal import Decimal
    decimal.getcontext().prec = 1000  # 运算精度,默认值 28
    sqrt5 = Decimal(5).sqrt()
    _1 = Decimal(1)
    _2 = Decimal(2)
    return int(_1 / sqrt5 * ((_1 + sqrt5) / _2) ** n + _1 / _2)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值