{"id":398,"date":"2013-12-27T22:25:47","date_gmt":"2013-12-28T06:25:47","guid":{"rendered":"http:\/\/blog.richardkiss.com\/?p=398"},"modified":"2021-02-05T17:30:13","modified_gmt":"2021-02-06T01:30:13","slug":"calculating-fibonacci-numbers-quickly-and-exactly","status":"publish","type":"post","link":"https:\/\/blog.richardkiss.com\/?p=398","title":{"rendered":"Calculating Fibonacci Numbers, Quickly and Exactly"},"content":{"rendered":"\n<p>The well-known Fibonacci series \\(F_n\\) can be defined as follows:<\/p>\n<p>\\(F_n =<br \/>\n\\begin{cases}<br \/>\n0 &#038; n = 0 \\\\<br \/>\n1 &#038; n = 1 \\\\<br \/>\nF_{n-2} + F_{n-1} &#038; n \\ge 2\\\\<br \/>\n\\end{cases}\\)<\/p>\n<p>Let&#8217;s use a few facts about matrices to find a quick way to calculate terms in this famous series.<\/p>\n<p><strong>Lemma<\/strong><\/p>\n<p>Let \\(A = \\begin{bmatrix}<br \/>\n0 &#038; 1 \\\\<br \/>\n1 &#038; 1<br \/>\n\\end{bmatrix}\\). Then \\(A^n = \\begin{bmatrix} F_{n-1} &#038; F_n \\\\ F_n &#038; F_{n+1} \\end{bmatrix}\\).<\/p>\n<p><strong>Proof<\/strong><\/p>\n<p>The \\(n = 1\\) case follows immediately from the definitions of \\(A \\text{ and } F_n\\).<\/p>\n<p>Suppose the statement is true for n. Then<br \/>\n$$\\begin{align}<br \/>\nA^{n+1} &#038; = A^n A \\\\<br \/>\n &#038; = \\begin{bmatrix} F_{n-1} &#038; F_n \\\\ F_n &#038; F_{n+1} \\end{bmatrix} \\begin{bmatrix} 0 &#038; 1 \\\\ 1 &#038; 1 \\end{bmatrix} \\\\<br \/>\n &#038; = \\begin{bmatrix} F_n &#038; F_{n-1} + F_n  \\\\ F_{n+1} &#038; F_n + F_{n+1} \\end{bmatrix} \\\\<br \/>\n &#038; = \\begin{bmatrix} F_n &#038; F_{n+1} \\\\ F_{n+1} &#038; F_{n+2} \\end{bmatrix}<br \/>\n\\end{align}$$<\/p>\n<p>And our result follows by induction. QED<\/p>\n<p>Now, notice that<\/p>\n<p>\\(\\begin{align}<br \/>\n\\begin{bmatrix} F_{2n-1} &#038; F_{2n} \\\\ F_{2n} &#038; F_{2n+1} \\end{bmatrix} &#038; = A^{2n} \\\\<br \/>\n&#038; = A^n A^n \\\\<br \/>\n&#038; = \\begin{bmatrix} F_{n-1} &#038; F_n \\\\ F_n &#038; F_{n+1} \\end{bmatrix} \\begin{bmatrix} F_{n-1} &#038; F_n \\\\ F_n &#038; F_{n+1} \\end{bmatrix} \\\\<br \/>\n&#038; = \\begin{bmatrix} F_{n-1}^2 + F_n ^ 2 &#038; F_{n-1} F_n + F_n F_{n+1} \\\\ F_{n-1} F_n + F_n F_{n+1} &#038; F_n^2 + F_{n+1} ^ 2 \\end{bmatrix}<br \/>\n\\end{align}\\)<\/p>\n<p>Using this identity, we can write \\(F_{2n}\\) and \\(F_{2n+1}\\) in terms of \\(F_n\\) and \\(F_{n+1}\\).<\/p>\n<p>\\(\\begin{align}<br \/>\nF_{2n} &#038; = F_{n-1} F_n + F_n F_{n+1} \\\\<br \/>\n&#038; = (F_{n+1} &#8211; F_n) F_n + F_n F_{n+1} \\\\<br \/>\n&#038; = F_n F_{n+1} &#8211; F_n^2 + F_n F_{n+1} \\\\<br \/>\n&#038; = 2 F_{n+1} F_n &#8211; F_n ^ 2<br \/>\n\\end{align} \\)<\/p>\n<p>\\(F_{2n+1} = F_{n}^2 + F_{n+1}^2\\)<\/p>\n<p>We now have a way of calculating \\(F_{2n}\\) and \\(F_{2n+1}\\) by calculating only a few of the smaller terms in the sequence. This yields some wildly efficient Python code:<\/p>\n<p><code><\/p>\n<pre>\r\ndef fib2(N):\r\n    if N == 0: return (0, 1)\r\n    half_N, is_N_odd = divmod(N, 2)\r\n    f_n, f_n_plus_1 = fib2(half_N)\r\n    f_n_squared = f_n * f_n\r\n    f_n_plus_1_squared = f_n_plus_1 * f_n_plus_1\r\n    f_2n = 2 * f_n * f_n_plus_1 - f_n_squared\r\n    f_2n_plus_1 = f_n_squared + f_n_plus_1_squared\r\n    if is_N_odd:\r\n        return (f_2n_plus_1, f_2n + f_2n_plus_1)\r\n    return (f_2n, f_2n_plus_1)\r\n\r\ndef fib(N):\r\n    return fib2(N)[0]\r\n<\/pre>\n<p><\/code><\/p>\n<p>And it&#8217;s fast! It&#8217;s \\(O(\\log N)\\) in fact:<\/p>\n<pre>\r\n$ pypy -m timeit -s 'import expfib' 'expfib.fib(500000)'\r\n10 loops, best of 3: 22.4 msec per loop\r\n<\/pre>\n<p>Compare to the na\u00efve, iterative version, which is \\(O(N)\\):<\/p>\n<p><code><\/p>\n<pre>\r\ndef fib2_linear(N):\r\n    f_n, f_n_plus_1 = (0, 1)\r\n    while N > 0:\r\n        N -= 1\r\n        f_n, f_n_plus_1 = f_n_plus_1, f_n + f_n_plus_1\r\n    return (f_n, f_n_plus_1)\r\n\r\ndef fib_linear(N):\r\n    return fib2_linear(N)[0]\r\n<\/pre>\n<p><\/code><\/p>\n<pre>\r\n$ pypy -m timeit -s 'import myfib' 'myfib.fib_linear(500000)'\r\n10 loops, best of 3: 2.76 sec per loop\r\n<\/pre>\n<p>This post was inspired by <a href=\"http:\/\/lee-phillips.org\/lispmath\/\">a post<\/a> by Lee Phillips and as an excuse to play around with <a href=\"http:\/\/www.mathjax.org\/\">MathJax<\/a>. The best guide I found for getting started is on <a href=\"http:\/\/meta.math.stackexchange.com\/questions\/5020\/mathjax-basic-tutorial-and-quick-reference\">Stack Exchange<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The well-known Fibonacci series \\(F_n\\) can be defined as follows: \\(F_n = \\begin{cases} 0 &#038; n = 0 \\\\ 1 &#038; n = 1 \\\\ F_{n-2} + F_{n-1} &#038; n \\ge 2\\\\ \\end{cases}\\) Let&#8217;s use a few facts about matrices to find a quick way to calculate terms in this famous series. Lemma Let \\(A &hellip; <a href=\"https:\/\/blog.richardkiss.com\/?p=398\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Calculating Fibonacci Numbers, Quickly and Exactly<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-398","post","type-post","status-publish","format-standard","hentry","category-computers"],"_links":{"self":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/398","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=398"}],"version-history":[{"count":107,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/398\/revisions"}],"predecessor-version":[{"id":505,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/398\/revisions\/505"}],"wp:attachment":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}