AN INTEGER FORMULA FOR FIBONACCI NUMBERS
https://blog.paulhankin.net/fibonacci/
This code, somewhat surprisingly, generates Fibonacci numbers.
def fib(n):
return (4 << n*(3+n)) // ((4 << 2*n) - (2 << n) - 1) & ((2 << n) - 1)
In this blog post, I'll explain where it comes from and how it works.
Before getting to explaining, I'll give a whirlwind background overview of Fibonacci numbers and how to compute them. If you're already a maths whiz, you can skip most of the introduction, quickly skim the section "Generating functions" and then read "An integer formula".
Overview
The Fibonacci numbers are a well-known sequence of numbers:
\]
The nth number in the sequence is defined to be the sum of the previous two, or formally by this recurrence relation:
\mathrm{Fib}(0) &=& 1 \\
\mathrm{Fib}(1) &=& 1 \\
\mathrm{Fib}(n) &=& \mathrm{Fib}(n - 1) + \mathrm{Fib}(n - 2)
\end{eqnarray}
\]
I've chosen to start the sequence at index 0 rather than the more usual 1.
Computing Fibonacci numbers
There's a few different reasonably well-known ways of computing the sequence. The obvious recursive implementation is slow:
def fib_recursive(n):
if n < 2: return 1
return fib_recursive(n - 1) + fib_recursive(n - 2)
An iterative implementation works in O(n) operations:
def fib_iter(n):
a, b = 1, 1
for _ in xrange(n):
a, b = a + b, a
return b
And a slightly less well-known matrix power implementation works in O(log n) operations.
def fib_matpow(n):
m = numpy.matrix('1 1 ; 1 0') ** n
return m.item(0)
The last method works by considering the a and b in fib_iter as sequences, and noting that
a_{n+1} \\
b_{n+1} \\
\end{matrix}\right) =
\left(\begin{matrix}
1 & 1 \\
1 & 0 \\
\end{matrix}\right)
\left(\begin{matrix}
a_n \\
b_n \\
\end{matrix}\right)
\]
From which follows
a_{n} \\
b_{n} \end{array} \right) =
\left( \begin{array}{cc}
1 & 1 \\
1 & 0 \end{array} \right) ^ n
\left( \begin{array}{c}
1 \\
1 \end{array} \right)
\]
and so if \(m = \left(\begin{matrix}
1 & 1 \\
1 & 0 \end{matrix} \right)^n\) then \(b_n = m_{11}\) (noting that unlike Python, matrix indexes are usually 1-based).
It's O(log n) based on the assumption that numpy's matrix power does something like exponentation by squaring.
Another method is to find a closed form for the solution of the recurrence relation. This leads to the real-valued formula: Fib(n)=(ϕn+1−ψn+1)/5‾√) where ϕ=(1+5‾√)/2 and ψ=(1−5‾√)/2. The practical flaw in this method is that it requires arbitrary precision real-valued arithmetic, but it works for small n.
def fib_phi(n):
phi = (1 + math.sqrt(5)) / 2.0
psi = (1 - math.sqrt(5)) / 2.0
return int((phi ** (n+1) - psi ** (n+1)) / math.sqrt(5))
Generating Functions
A generating function for an arbitrary sequence an is the infinite sum Σnanxn. In the specific case of the Fibonacci numbers, that means ΣnFib(n)xn. In words, it's an infinite power series, with the coefficient of xn being the nth Fibonacci number.
Now,
Fib(n+2)=Fib(n+1)+Fib(n)
Multiplying by xn+2 and summing over all n, we get:
ΣnFib(n+2)xn+2=ΣnFib(n+1)xn+2+ΣnFib(n)xn+2
If we let F(x) to be the generating function of Fib, which is defined to be ΣnFib(n)xn then this equation can be simplified:
F(x)−x−1=x(F(x)−1)+x2F(x)
and simplifying,
F(x)=xF(x)+x2F(x)+1
We can solve this equation for F to get
F(x)=11−x−x2
It's surprising that we've managed to find a small and simple formula which captures all of the Fibonacci numbers, but it's not yet obvious how we can use it. We'll get to that in the next section.
A technical aside is that we're going to want to evaluate F at some values of x, and we'd like the power series to converge. We know the Fibonacci numbers grow like ϕn and that geometric series Σnan converge if |a|<1, so we know that if |x|<1/ϕ≃0.618 then the power series converges.
An integer formula
Now we're ready to start understanding the Python code.
To get the intuition behind the formula, we'll evaluate the generating function F at 10−3.
F(x)=11−x−x2F(10−3)=11−10−3−10−6=1.001002003005008013021034055089144233377610988599588187…
Interestingly, we can see some Fibonacci numbers in this decimal expansion: 1,1,2,3,5,8,13,21,34,55,89. That seems magical and surprising, but it's because F(10−3)=Fib(0)+Fib(1)/103+Fib(2)/106+Fib(3)/109+….
In this example, the Fibonacci numbers are spaced out at multiples of 1/1000, which means once they start getting bigger that 1000 they'll start interfering with their neighbours. We can see that starting at 988 in the computation of F(10−3) above: the correct Fibonacci number is 987, but there's a 1 overflowed from the next number in the sequence causing an off-by-one error. This breaks the pattern from then on.
But, for any value of n, we can arrange for the negative power of 10 to be large enough that overflows don't disturb the nth Fibonacci. For now, we'll just assume that there's some k which makes 10−k sufficient, and we'll come back to picking it later.
Also, since we'd like to use integer maths (because it's easier to code), let's multiply by 10kn, which also puts the nth Fibonacci number just to the left of the decimal point, and simplify the equation.
10knF(10−k)=10kn1−10−k−10−2k=10kn+2k102k−10k−1
If we take this result modulo 10k, we'll get the nth Fibonacci number (again, assuming we've picked k large enough).
Before proceeding, let's switch to base 2 rather than base 10, which changes nothing but will make it easier to program.
2knF(2−k)=2k(n+2)22k−2k−1
Now all that's left is to pick a value of k large enough so that Fib(n+1)<2k. We know that the Fibonacci numbers grow like ϕn, and ϕ<2, so k=n+1 is safe.
So! Putting that together:
Fib(n)≡2(n+1)nF(2−(n+1)) mod 2n+1≡2(n+1)(n+2)(2n+1)2−2n+1−1 mod 2n+1≡2(n+1)(n+2)22n+2−2n+1−1 mod 2n+1
If we use left-shift notation that's available in python, where a<<k=a⋅2k then we can write this as:
Fib(n)≡4<<n(3+n)(4<<2n)−(2<<n)−1mod (2<<n)
Observing that mod (2<<n) can be expressed as the bitwise and (&) of (2<<n)−1, we reconstruct our original Python program:
def fib(n):
return (4 << n*(3+n)) // ((4 << 2*n) - (2 << n) - 1) & ((2 << n) - 1)
Although it's curious to find a non-iterative, closed-form solution, this isn't a practical method at all. We're doing integer arithmetic with integers of size O(n2) bits, and in fact, before performing the final bit-wise and, we've got an integer that is the first n Fibonacci numbers concatenated together!
AN INTEGER FORMULA FOR FIBONACCI NUMBERS的更多相关文章
- Fibonacci Numbers
Fibonacci Numbers Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- UVa-11582:Colossal Fibonacci Numbers!(模算术)
这是个开心的题目,因为既可以自己翻译,代码又好写ヾ(๑╹◡╹)ノ" The i’th Fibonacci number f(i) is recursively defined in the f ...
- [Amazon] Program for Fibonacci numbers 斐波那契数列
The Fibonacci numbers are the numbers in the following integer sequence. 0, 1, 1, 2, 3, 5, 8, 13, 21 ...
- codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...
- Codeforces 446-C DZY Loves Fibonacci Numbers 同余 线段树 斐波那契数列
C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...
- cf446C DZY Loves Fibonacci Numbers
C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...
- Codeforces Round #FF 446 C. DZY Loves Fibonacci Numbers
參考:http://www.cnblogs.com/chanme/p/3843859.html 然后我看到在别人的AC的方法里还有这么一种神方法,他预先设定了一个阈值K,当当前的更新操作数j<K ...
- HDU 3117 Fibonacci Numbers(围绕四个租赁斐波那契,通过计++乘坐高速动力矩阵)
HDU 3117 Fibonacci Numbers(斐波那契前后四位,打表+取对+矩阵高速幂) ACM 题目地址:HDU 3117 Fibonacci Numbers 题意: 求第n个斐波那契数的 ...
- Codeforces446C - DZY Loves Fibonacci Numbers
Portal Description 给出一个\(n(n\leq3\times10^5)\)个数的序列,进行\(m(m\leq3\times10^5)\)次操作,操作有两种: 给区间\([L,R]\) ...
随机推荐
- ASP.NET中<%=%>、<%%>、<%@%>、<%#%>的用法与区别
1.<%= %> 里面放变量名,获取后台的变量值,直接输入变量到页面上,里面放的变量名,未经过encode eg: 后台: seession["ab"]=ab; 前台: ...
- ts 学习笔记 - 进阶篇 1
目录 进阶 类型别名 字符串字面量类型 元祖 例子 越界的元素 枚举 手动赋值 常数项和计算所得项 常数枚举 外部枚举 进阶 类型别名 类型别名用来给一个类型起个新名字 type Name = str ...
- 【JavaWeb】EL表达式&过滤器&监听器
EL表达式和JSTL EL表达式 EL表达式概述 基本概念 EL表达式,全称是Expression Language.意为表达式语言.它是Servlet规范中的一部分,是JSP2.0规范加入的内容.其 ...
- 「必知必会」最细致的 ArrayList 原理分析
从今天开始也正式开 JDK 原理分析的坑了,其实写源码分析的目的不再是像以前一样搞懂原理,更重要的是看看他们编码风格更进一步体会到他们的设计思想.看源码前先自己实现一个再比对也许会有不一样的收获! ...
- CTF之隐写总结
目测要更很久,因为今年有一件非常重要的事要完成,希望一切顺利 All The Best.
- noip模拟35[第一次4题·裂了]
noip模拟35 solutions 这是我第一次这么正式的考四个题,因为这四个题都出自同一个出题人,并不是拼盘拼出来的. 但是考得非常的不好,因为题非常难而且一直想睡觉.. 有好多我根本就不会的算法 ...
- 实战爬取Plati官网游戏实时最低价格-Python
需要修改url中的id_r="这个",这个id需要从Battlefield V (plati.ru)中获取,其实也是这个链接中的#s24235. 配合了e-mail推送,其实这个e ...
- USB 3.0 开发要点
最近在公司里安排了我一个新的任务,那就是USB3.0的研发.对于我之前都是做ARM+LINUX和单片机软件研发的来说,虽然之前都是做驱动程序和应用程序,但是没有做与USB 相关的开发,毕竟这是第一次. ...
- MySQL基本概念及增删改查操作
SQL.DB.DBMS关系 DB: DataBase(数据库,数据库实际上在硬盘上以文件的形式存在) DBMS: DataBase Management System(数据库管理系统,常见的有:MyS ...
- ☕【Java技术指南】「OpenJDK专题」想不想编译属于你自己的JDK呢?(Windows10环境)
Win10下编译OpenJDK8 编译环境 Windows10专业版64位: 编译前准备 Tip: 以下软件的安装和解压目录尽量不要包含中文或空格,不然可能会出现问题 安装 Visual Studio ...