Python n的第n个斐波那契数大到10^19?
我正试着做一个程序来找出1Python n的第n个斐波那契数大到10^19?,python,python-2.7,dynamic-programming,fibonacci,Python,Python 2.7,Dynamic Programming,Fibonacci,我正试着做一个程序来找出1
memo = {}
def fib(n):
if n in memo:
return memo[n]
if n <= 2:
f = 1
else:
f = fib(n-1) + fib(n-2)
memo[n]=f
return f
print fib(input()) % 1000000007
memo={}
def纤维(n):
如果备忘录中有n:
返回备忘录[n]
如果nPython的默认值为1000(通常)。要了解系统的确切限制,请执行以下操作:
>>> import sys
>>> sys.getrecursionlimit()
首先,如果您想递归地编写此代码,并且您使用的是Python 3.2及更高版本(从print
语句判断,您看起来不是这样的),那么您可以这样使用:
导入工具
@functools.lru_cache()
def纤维(n):
如果n在O(n)效率下,你将永远无法到达那里。与代码无关,但描述了一种在O(log(n))效率中查找F(n)的方法
F(2n-1)=F(n-1)^2+F(n)^2
F(2n)=(2*F(n-1)+F(n))*F(n)
你不仅可以这样做,而且还可以递归地这样做。当N为10^19时获取第N个fibonacci数是不可行的,如果你用天真的方法来做的话(至少我猜它不会起作用)
有一个更好的方法。这种技术适用于很多类似这样的系列。它叫“世界杯”
在哪里
你可以这样想:
你有一些矩阵可以把向量A转换成B:
填写这些条目很容易。特别的是这是一个矩阵算子,如果我们想要第1000个斐波那契数,我们只需要做矩阵乘法
你可以用一个循环来实现这一点,但要达到10^19还需要相当长的时间,而进行10^19矩阵乘法(即使它们很小)也需要相当长的时间
相反,我们走另一条捷径。x^N可以重写为幂的乘积,其中它们的和为N,即
x**100 == x**90 * x**10
因此,目标是在不进行大量计算的情况下获得指数中的大量数字:
x**2
与x*x
一样困难-它们花费的时间相同。但是x*x*x*x
给出了与(x**2)**2
相同的答案,同时需要额外的乘法运算。当你进入更高的权力时,收益会更多。所以如果你把指数分解成2的幂(任何幂都有效,但这是最简单的情况)
i、 e
所以你要做的是,计算出你想要达到的总功率的二次幂,然后取Q
矩阵的二次幂的乘积
这似乎对我有用:
fib_matrix = [[1,1],
[1,0]]
def matrix_square(A, mod):
return mat_mult(A,A,mod)
def mat_mult(A,B, mod):
if mod is not None:
return [[(A[0][0]*B[0][0] + A[0][1]*B[1][0])%mod, (A[0][0]*B[0][1] + A[0][1]*B[1][1])%mod],
[(A[1][0]*B[0][0] + A[1][1]*B[1][0])%mod, (A[1][0]*B[0][1] + A[1][1]*B[1][1])%mod]]
def matrix_pow(M, power, mod):
#Special definition for power=0:
if power <= 0:
return M
powers = list(reversed([True if i=="1" else False for i in bin(power)[2:]])) #Order is 1,2,4,8,16,...
matrices = [None for _ in powers]
matrices[0] = M
for i in range(1,len(powers)):
matrices[i] = matrix_square(matrices[i-1], mod)
result = None
for matrix, power in zip(matrices, powers):
if power:
if result is None:
result = matrix
else:
result = mat_mult(result, matrix, mod)
return result
print matrix_pow(fib_matrix, 10**19, 1000000007)[0][1]
fib_矩阵=[[1,1],
[1,0]]
def矩阵_平方(A,mod):
返回材料(A、A、mod)
def材料(A、B、mod):
如果mod不是None:
返回[[A[0][0]*B[0][0]+A[0][1]*B[1][0]%mod,(A[0][0]*B[0][1]+A[0][1]*B[1][1]%mod,
[A[1][0]*B[0][0]+A[1][1]*B[1][0]%mod,(A[1][0]*B[0][1]+A[1][1]*B[1][1]%mod]
def矩阵_功率(M、功率、mod):
#功率=0的特殊定义:
如果power我不认为您可以使用此选项升级到1E19,但以下是如何避免双重溢出和递归深度限制:
import decimal
import operator
def decimal_range(start, stop, step=1):
"""Provides an alternative to `xrange` for very high numbers."""
proceed = operator.lt
while proceed(start, stop):
yield start
start += step
def fib(n):
"""
Computes Fibonacci numbers using decimal.Decimal for high
precision and without recursion
"""
a, b = decimal.Decimal(0), decimal.Decimal(1)
for i in decimal_range(0, n):
a, b = b, a + b
return a
在我的机器上,计算1E6需要26.5秒,但我不能保证结果的正确性:
In [26]: %time f2(n)
CPU times: user 26.4 s, sys: 130 ms, total: 26.5 s
Wall time: 26.5 s
Out[26]: Decimal('1.953282128707757731632014830E+208987')
迭代器是通过最小的改动从中获取的,同时可以找到fib
函数。您可以使用循环而不是递归。什么不起作用?您将达到递归深度限制。我得到无效响应。除了创建堆栈溢出的问题外,您可能只想存储最后两个Fibbonachi数,这样您就不会创建10^19个大整数的数组。此外,可能还可以查看一个多精度整数库,如gmpy2。OP没有很好地描述它,但我很确定OP的%100000007
暗示了一个事实,即我们只需要得到mod 100000007的答案。不管怎样,矩阵形式(或者你喜欢的简化公式)可能是必要的,因为你无法对上限进行~10^19次迭代。@DSM你这样做的方式是首先不进行迭代。有一种更有效的方法来计算斐波那契数。@威尔:我不确定你的意思,因为我刚才说迭代是不可能的。使用矩阵乘法或等效的约化公式(正如我刚才所做的——我看到John Pirie刚刚发布的),我可以在大约190纳秒的时间内得到正确的答案。@DSM我只是在里面键入了一个类似这样的答案:-/@DSM我没有正确阅读你写的内容。我同意你的观点。+1,尽管这个公式对于直接计算n
到10^19
的F(n)
仍然是没有希望的。(这里没有公式可以工作:结果太大,无法存储。)不过,再加上约化模100000007
,这就行了。@Mark Dickinson:在对数(n)复杂度方面,我认为这个公式需要50次左右的迭代才能达到,不是吗?太多的辅助值无法计算?@JohnPirie:我想他只是指Fib(10^19)~2.2041233236015342e+2089876402499787337,所以除非我们减少,否则我们就被套住了。:-)@帝斯曼:啊,所以一个简单的估计也同样有效;感谢you@JohnPirie:是的,DSM说了什么。OP没有直接这么说,但看起来他真正想要的是减少模F(n)
而不是F(n)
本身。(听起来像是典型的Project Euler风格的挑战问题,而不是真实世界的计算。)如果你真的这么做了,那么你应该对矩阵进行对角化——然后你可以轻松地将其提升到任意幂次。嘿@will,这对斐波那契序列很有帮助。但是,有点离题了,但我希望你们能帮我-我有一个整数序列,其中有2n和2n+1项的自定义公式。你知道我是否可以用类似于斐波那契序列的方法来处理这个问题,并为自定义序列生成类似的Q矩阵吗?谢谢什么是递归关系?如果偏移量是固定的。
fib_matrix = [[1,1],
[1,0]]
def matrix_square(A, mod):
return mat_mult(A,A,mod)
def mat_mult(A,B, mod):
if mod is not None:
return [[(A[0][0]*B[0][0] + A[0][1]*B[1][0])%mod, (A[0][0]*B[0][1] + A[0][1]*B[1][1])%mod],
[(A[1][0]*B[0][0] + A[1][1]*B[1][0])%mod, (A[1][0]*B[0][1] + A[1][1]*B[1][1])%mod]]
def matrix_pow(M, power, mod):
#Special definition for power=0:
if power <= 0:
return M
powers = list(reversed([True if i=="1" else False for i in bin(power)[2:]])) #Order is 1,2,4,8,16,...
matrices = [None for _ in powers]
matrices[0] = M
for i in range(1,len(powers)):
matrices[i] = matrix_square(matrices[i-1], mod)
result = None
for matrix, power in zip(matrices, powers):
if power:
if result is None:
result = matrix
else:
result = mat_mult(result, matrix, mod)
return result
print matrix_pow(fib_matrix, 10**19, 1000000007)[0][1]
import decimal
import operator
def decimal_range(start, stop, step=1):
"""Provides an alternative to `xrange` for very high numbers."""
proceed = operator.lt
while proceed(start, stop):
yield start
start += step
def fib(n):
"""
Computes Fibonacci numbers using decimal.Decimal for high
precision and without recursion
"""
a, b = decimal.Decimal(0), decimal.Decimal(1)
for i in decimal_range(0, n):
a, b = b, a + b
return a
In [26]: %time f2(n)
CPU times: user 26.4 s, sys: 130 ms, total: 26.5 s
Wall time: 26.5 s
Out[26]: Decimal('1.953282128707757731632014830E+208987')