この記事は,
旧ブログ から移植された記事です. よって, その内容として,
旧ブログ に依存した文脈が含まれている可能性があります. 予めご了承下さい.
フィボナッチ数列を以下の漸化式で定義する.
f n + 2 = f n + 1 + f n ( n ≥ 0 ) f_{n+2} = f_{n+1} + f_n\ (n\geq 0) f n + 2 = f n + 1 + f n ( n ≥ 0 )
ここで, 初項と第二項をそれぞれ a 1 = 1 , a 2 = 1 a_1=1, a_2=1 a 1 = 1 , a 2 = 1 とする.
各項を f n + 2 → c 2 、 f n + 1 → c 、 f n → 1 f_{n+2}\rightarrow c^2、f_{n+1}\rightarrow c、f_n\rightarrow 1 f n + 2 → c 2 、 f n + 1 → c 、 f n → 1 と置き換えると
c 2 = c + 1 (1) c^2=c+1\tag{1} c 2 = c + 1 ( 1 ) が得られる.
この解は c = 1 ± 5 2 c=\dfrac{1\pm{\sqrt{5}}}{2} c = 2 1 ± 5 となる.
ここで, ψ = 1 − 5 2 , ϕ = 1 + 5 2 \psi = \dfrac{1-\sqrt{5}}{2}, \phi = \dfrac{1+\sqrt{5}}{2} ψ = 2 1 − 5 , ϕ = 2 1 + 5 と置く.
フィボナッチ数列の漸化式の特性方程式の解は ( 1 ) (1) ( 1 ) の解より ψ , ϕ \psi, \phi ψ , ϕ
であるから
f n + 2 = f n + 1 + f n ⇔ { f n + 2 − ψ f n + 1 = ϕ ( f n + 1 − ψ f n ) f n + 2 − ϕ f n + 1 = ψ ( f n + 1 − ϕ f n ) f_{n+2}=f_{n+1}+f_{n}\Leftrightarrow\begin{cases}f_{n+2}-\psi f_{n+1}=\phi(f_{n+1}-\psi f_n) \\
f_{n+2}-\phi f_{n+1}=\psi(f_{n+1}-\phi f_n)\end{cases} f n + 2 = f n + 1 + f n ⇔ { f n + 2 − ψ f n + 1 = ϕ ( f n + 1 − ψ f n ) f n + 2 − ϕ f n + 1 = ψ ( f n + 1 − ϕ f n )
と変形できる. いま b n = f n + 1 − ψ f n , c n = f n + 1 − ϕ f n b_n=f_{n+1}-\psi f_n, c_n=f_{n+1}-\phi f_n b n = f n + 1 − ψ f n , c n = f n + 1 − ϕ f n と置くと次の漸化式が得られる.
{ b n + 1 = ϕ b n c n + 1 = ψ c n \begin{cases}b_{n+1}=\phi b_n\\c_{n+1}=\psi c_n\end{cases} { b n + 1 = ϕ b n c n + 1 = ψ c n
また f 1 = 1 , f 2 = 1 f_1=1, f_2=1 f 1 = 1 , f 2 = 1 より
{ b 1 = f 2 − ψ f 1 = 1 − ψ c 1 = f 2 − ϕ f 1 = 1 − ϕ \begin{cases}b_1=f_2-\psi f_1=1-\psi\\
c_1=f_2-\phi f_1=1-\phi\end{cases} { b 1 = f 2 − ψ f 1 = 1 − ψ c 1 = f 2 − ϕ f 1 = 1 − ϕ
として, 数列 b n {b_n} b n と数列 c n {c_n} c n の初項が求まる.
故に, 数列 b n {b_n} b n は初項 1 − ψ 1-\psi 1 − ψ , 公比 ϕ \phi ϕ の等比数列であるから,
b n = ( 1 − ψ ) ϕ n − 1 b_n = (1-\psi)\phi^{n-1} b n = ( 1 − ψ ) ϕ n − 1 , 数列 c n {c_n} c n は初項 1 − ϕ 1-\phi 1 − ϕ ,
公比 ψ \psi ψ の等比数列であるから, c n = ( 1 − ϕ ) ψ n − 1 c_n = (1-\phi)\psi^{n-1} c n = ( 1 − ϕ ) ψ n − 1 といえる.
さらに b n , c n b_n, c_n b n , c n を上記の定義より代入すると,
{ ϕ n = b n = f n + 1 − ψ f n p s i n = c n = f n + 1 − ϕ f n \begin{cases} \phi^n=b_n=f_{n+1}-\psi f_n\\psi^n=c_n=f_{n+1}-\phi f_n\end{cases} { ϕ n = b n = f n + 1 − ψ f n p s i n = c n = f n + 1 − ϕ f n が得られる.
上の式から下の式を引くと ϕ n − ψ n = − ψ f n + ϕ f n = ( ϕ − ψ ) f n \phi^n-\psi^n=-\psi f_n+\phi f_n=(\phi-\psi)f_n ϕ n − ψ n = − ψ f n + ϕ f n = ( ϕ − ψ ) f n であるから,
一般項 f n f_n f n は f n = 1 ϕ − ψ ( ϕ n − ψ n ) f_n=\dfrac{1}{\phi-\psi}( \phi^n-\psi^n) f n = ϕ − ψ 1 ( ϕ n − ψ n )
∴ \therefore ∴ ψ , ϕ \psi, \phi ψ , ϕ を上記の定義より代入すると,
以下のフィボナッチ数列の一般項が求まる.
f n = 1 5 { ( 1 + 5 2 ) n − ( 1 − 5 2 ) n } f_n=\dfrac{1}{\sqrt{5}}\left\{(\dfrac{1+\sqrt{5}}{2})^{n}-(\dfrac{1-\sqrt{5}}{2})^{n} \right\} f n = 5 1 { ( 2 1 + 5 ) n − ( 2 1 − 5 ) n }
数値計算で確認してみよう.
{-# OPTIONS_GHC -Wall #-}
import System.Random (getStdRandom, randomR)
import System.IO (stderr)
import Test.HUnit (Test (TestList ), (~:), (~?=), runTestText, putTextToHandle)
import Control.Monad (void)
fibGeneralTerm :: Int -> Integer
fibGeneralTerm = let phi = (1 + sqrt 5 ) / 2 :: Double in floor . (+ 0.5 ). (/ sqrt 5 ). (phi ^^ )
fib :: [Integer ]
fib = 0 : 1 : zipWith (+ ) fib (tail fib)
mkTestList :: Int -> Int -> Int -> IO Test
mkTestList b l times = TestList <$> loop 1
where
loop i
| i <= times = do
r <- getStdRandom $ randomR (b, l)
(: ) ("fib test: " ++ show i ++ ", value: " ++ show r ~: fibGeneralTerm r ~?= fib !! r) <$> loop (succ i)
| otherwise = return []
main :: IO ()
main = mkTestList 0 50 5 >>= void. runTestText (putTextToHandle stderr False )
cases: 5 Tried: 5 Errors: 0 Failures: 0
上で導出した式の第二項の最大値は 1 5 ≈ 0.447 \displaystyle \dfrac{1}{\sqrt{5}} \approx 0.447 5 1 ≈ 0.447
が最大であることから, 正確な整数値を求めるのには第二項を略してしまって 0.5 0.5 0.5 を加え,
床関数を作用させれば十分である. 上のコードでもそれを利用している.
f n = ⌊ ϕ n 5 + 1 2 ⌋ f_n=\left\lfloor \dfrac{\phi^{n}}{\sqrt{5}}+\dfrac{1}{2} \right\rfloor f n = ⌊ 5 ϕ n + 2 1 ⌋
ただし, 計算処理内で浮動小数点数による加算を用いていることから, 大きな値になればなるほど絶対誤差が生じていくことになる. 今回の実行結果も, たまたまその誤差が埋もれただけであってfibGeneralTerm
の実行結果に対する厳密な信憑性はない.