如何找到最近的斐波那契数列?
How to find the nearest Fibonacci Series number?
我的下一步是,如果输入不在斐波那契数列中,程序必须给出一个输出,其中的数字在最接近输入的数列中。我不知道如何进行,有人可以帮助我吗?
def fibs():
a,b = 0,1
yield a
yield b
while True:
a,b = b,a+b
yield b
n = int(input("please, enter a number: "))
for fib in fibs():
if n == fib:
print("Yes! Your number is a Fibonacci number!")
break
if fib > n:
print("No! Your number is not a Fibonacci number!")
break
如果您不介意调用额外的生成器,则无需保留之前的斐波那契。
首先将生成器存储在一个变量中。
gen = fibs()
n = int(input("please, enter a number: "))
for fib in gen:
if n == fib:
print("Yes! Your number is a Fibonacci number!")
break
if fib > n:
print("No! Your number is not a Fibonacci number!")
next_fib = next(gen)
prev = next_fib - fib
closest = prev if n - prev < fib - n else fib # Search for Python ternary operator
# If you are a stranger to this line of code.
print("The closest fibonacci number to your entry is %s" % closest)
break
编辑: 我先用gen.next()
得到下一个yield的值,但是我忘了在Python 3中,它被重命名为gen.__next__()
的用法。请小心使用。 next(gen)
是两个 Python 版本的预期用法。
您可以压缩 fibs
自身:
n = int(input("please, enter a number: "))
for fib, next_fib in itertools.izip(fibs(), itertools.islice(fibs(), 1, None)):
if n == fib:
print("Yes! Your number is a Fibonacci number!")
break
if next_fib > n:
closest = fib if n - fib < next_fib - n else next_fib
print("The closest Fibonacci number is {}".format(closest))
break
您可以使用 itertools.tee
稍微优化一下。
这是使用生成器的简单方法,适用于测试小数。
def fibs():
a,b = 0,1
yield a
yield b
while True:
a,b = b,a+b
yield b
def nearest_fib(n):
''' If n is a Fibonacci number return True and n
Otherwise, return False and the nearest Fibonacci number
'''
for fib in fibs():
if fib == n:
return True, n
elif fib < n:
prev = fib
else:
# Is n closest to prev or to fib?
if n - prev < fib - n:
return False, prev
else:
return False, fib
# Test
for i in range(35):
print(i, nearest_fib(i))
输出
0 (True, 0)
1 (True, 1)
2 (True, 2)
3 (True, 3)
4 (False, 5)
5 (True, 5)
6 (False, 5)
7 (False, 8)
8 (True, 8)
9 (False, 8)
10 (False, 8)
11 (False, 13)
12 (False, 13)
13 (True, 13)
14 (False, 13)
15 (False, 13)
16 (False, 13)
17 (False, 21)
18 (False, 21)
19 (False, 21)
20 (False, 21)
21 (True, 21)
22 (False, 21)
23 (False, 21)
24 (False, 21)
25 (False, 21)
26 (False, 21)
27 (False, 21)
28 (False, 34)
29 (False, 34)
30 (False, 34)
31 (False, 34)
32 (False, 34)
33 (False, 34)
34 (True, 34)
更新
这里有一个更有效的方法,它使用 Binet's formula to first approximate y: F(y) = n. It then uses a pair of identities related to the matrix form(可以在 O(log(n)) 时间内计算 F(n))递归地找到最接近 n 的斐波那契数。递归非常快,因为它使用缓存来保存已经计算过的值。在没有缓存的情况下,该算法的速度与 Rockybilly 的速度大致相同。
from math import log, sqrt
def fast_fib(n, cache={0: 0, 1: 1}):
if n in cache:
return cache[n]
m = (n + 1) // 2
a, b = fast_fib(m - 1), fast_fib(m)
fib = a * a + b * b if n & 1 else (2 * a + b) * b
cache[n] = fib
return fib
logroot5 = log(5) / 2
logphi = log((1 + 5 ** 0.5) / 2)
def nearest_fib(n):
if n == 0:
return 0
# Approximate by inverting the large term of Binet's formula
y = int((log(n) + logroot5) / logphi)
lo = fast_fib(y)
hi = fast_fib(y + 1)
return lo if n - lo < hi - n else hi
for i in range(35):
print(i, nearest_fib(i))
输出
0 0
1 1
2 2
3 3
4 5
5 5
6 5
7 8
8 8
9 8
10 8
11 13
12 13
13 13
14 13
15 13
16 13
17 21
18 21
19 21
20 21
21 21
22 21
23 21
24 21
25 21
26 21
27 21
28 34
29 34
30 34
31 34
32 34
33 34
34 34
请注意,fast_fib
使用 default mutable argument 作为缓存,但这没关系,因为我们希望 缓存记住其以前的内容。
在我的速度测试中,默认的可变参数缓存比任何其他形式的缓存都快,但它的缺点是无法从函数外部清除缓存,并且如果您向函数添加缓存逻辑当您不想清除缓存时,清除它会影响大多数调用的性能。
更新
实际上可以从函数外部清除默认的可变参数缓存。我们可以通过函数的 .__default__
属性(或旧版本 Python 2 中的 .func_defaults
访问函数的默认参数;.__default__
在 Python 2.6 中有效,但在2.5).
例如,
d = fast_fib.__defaults__[0]
d.clear()
d.update({0: 0, 1: 1})
这里有一些代码(在 Python 2 和 Python 3 上运行)对为此问题提交的一些算法执行计时测试。 Rockybilly 与我的第一个版本非常相似,只是它避免了必须保存以前的值。我还使 OP 的 fibs
生成器更加紧凑。
Douglas 代码适用于小数,或者当参数实际上是斐波那契数时,但由于缓慢的逐一搜索。我已经能够通过避免重新计算各种数量来稍微优化它,但这对 运行 速度没有太大影响。
在这个版本中,我的 fast_fib()
函数使用了一个全局缓存,这样它就可以在测试之间被清除,从而使计时更加公平。
#!/usr/bin/env python3
""" Find the nearest Fibonacci number to a given integer
Test speeds of various algorithms
See
Written by PM 2Ring 2016.11.19
Incorporating code by Rockybilly and Douglas
"""
from __future__ import print_function, division
from math import log, sqrt
from time import time
def fibs():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
def nearest_fib_Rocky(n):
''' Find the nearest Fibonacci number to n '''
fibgen = fibs()
for fib in fibgen:
if fib == n:
return n
elif fib > n:
next_fib = next(fibgen)
return next_fib - fib if 2 * n < next_fib else fib
def nearest_fib_Doug(n):
a = 5 * n * n
if sqrt(a + 4)%1 == 0 or sqrt(a - 4)%1 == 0:
return n
c = 1
while True:
m = n + c
a = 5 * m * m
if sqrt(a + 4)%1 == 0 or sqrt(a - 4)%1 == 0:
return m
m = n - c
a = 5 * m * m
if sqrt(a + 4)%1 == 0 or sqrt(a - 4)%1 == 0:
return m
c += 1
cache={0: 0, 1: 1}
def fast_fib(n):
if n in cache:
return cache[n]
m = (n + 1) // 2
a, b = fast_fib(m - 1), fast_fib(m)
fib = a * a + b * b if n & 1 else (2 * a + b) * b
cache[n] = fib
return fib
logroot5 = log(5) / 2
logphi = log((1 + 5 ** 0.5) / 2)
def nearest_fib_PM2R(n):
if n == 0:
return 0
# Approximate by inverting the large term of Binet's formula
y = int((log(n) + logroot5) / logphi)
lo = fast_fib(y)
hi = fast_fib(y + 1)
return lo if n - lo < hi - n else hi
funcs = (
nearest_fib_PM2R,
nearest_fib_Rocky,
nearest_fib_Doug,
)
# Verify that all the functions return the same result
def verify(lo, hi):
for n in range(lo, hi):
a = [f(n) for f in funcs]
head, tail = a[0], a[1:]
if not all(head == u for u in tail):
print('Error:', n, a)
return False
else:
print('Ok')
return True
def time_test(lo, hi):
print('lo =', lo, 'hi =', hi)
for f in funcs:
start = time()
for n in range(lo, hi):
f(n)
t = time() - start
print('{0:18}: {1}'.format(f.__name__, t))
print()
verify(0, 1000)
cache={0: 0, 1: 1}
time_test(0, 1000)
funcs = funcs[:-1]
cache={0: 0, 1: 1}
time_test(1000, 50000)
典型输出
Ok
lo = 0 hi = 1000
nearest_fib_PM2R : 0.005465507507324219
nearest_fib_Rocky : 0.02432560920715332
nearest_fib_Doug : 0.45461463928222656
lo = 1000 hi = 50000
nearest_fib_PM2R : 0.26880311965942383
nearest_fib_Rocky : 1.266334056854248
这些时间是在旧的 2GHz 32 位机器上 运行 Python 3.6 在 Linux 上。 Python 2.6 给出了类似的时间。
FWIW,Rockybilly 和我的代码都可以轻松处理非常大的数字。这是 time_test(10**1000, 10**1000 + 1000)
的计时输出:
nearest_fib_PM2R : 0.011492252349853516
nearest_fib_Rocky : 7.556792497634888
为什么这个方法行之有效:
这是一种不需要预先计算的方法,因此在检查非常大的数字时性能等方面非常棒。
程序:
from math import *
n = int(input("Enter a number:"))
if sqrt(5*n**2+4)%1==0 or sqrt(5*n**2-4)%1==0:
print("Your number is a Fibonacci number!")
else:
print("Your number is not a Fibonacci number.")
c = 0
while 1:
c += 1
if sqrt(5*(n+c)**2+4)%1==0 or sqrt(5*(n+c)**2-4)%1==0:
print("%s is the closest Fibonacci number to your entry." % str(n+c))
break
if sqrt(5*(n-c)**2+4)%1==0 or sqrt(5*(n-c)**2-4)%1==0:
print("%s is the closest Fibonacci number to your entry." % str(n-c))
break
解释:
如果 (5*n^2 + 4) 或 (5*n^2 – 4) 是一个完全平方数,则 n 是一个斐波那契数。
计划Input/Output
Enter a number: 9999999999
Your number is not a Fibonacci number.
9999816735 is the closest Fibonacci number to your entry.
Enter a number: 9999816735
Your number is a Fibonacci number!
我的下一步是,如果输入不在斐波那契数列中,程序必须给出一个输出,其中的数字在最接近输入的数列中。我不知道如何进行,有人可以帮助我吗?
def fibs():
a,b = 0,1
yield a
yield b
while True:
a,b = b,a+b
yield b
n = int(input("please, enter a number: "))
for fib in fibs():
if n == fib:
print("Yes! Your number is a Fibonacci number!")
break
if fib > n:
print("No! Your number is not a Fibonacci number!")
break
如果您不介意调用额外的生成器,则无需保留之前的斐波那契。
首先将生成器存储在一个变量中。
gen = fibs()
n = int(input("please, enter a number: "))
for fib in gen:
if n == fib:
print("Yes! Your number is a Fibonacci number!")
break
if fib > n:
print("No! Your number is not a Fibonacci number!")
next_fib = next(gen)
prev = next_fib - fib
closest = prev if n - prev < fib - n else fib # Search for Python ternary operator
# If you are a stranger to this line of code.
print("The closest fibonacci number to your entry is %s" % closest)
break
编辑: 我先用gen.next()
得到下一个yield的值,但是我忘了在Python 3中,它被重命名为gen.__next__()
的用法。请小心使用。 next(gen)
是两个 Python 版本的预期用法。
您可以压缩 fibs
自身:
n = int(input("please, enter a number: "))
for fib, next_fib in itertools.izip(fibs(), itertools.islice(fibs(), 1, None)):
if n == fib:
print("Yes! Your number is a Fibonacci number!")
break
if next_fib > n:
closest = fib if n - fib < next_fib - n else next_fib
print("The closest Fibonacci number is {}".format(closest))
break
您可以使用 itertools.tee
稍微优化一下。
这是使用生成器的简单方法,适用于测试小数。
def fibs():
a,b = 0,1
yield a
yield b
while True:
a,b = b,a+b
yield b
def nearest_fib(n):
''' If n is a Fibonacci number return True and n
Otherwise, return False and the nearest Fibonacci number
'''
for fib in fibs():
if fib == n:
return True, n
elif fib < n:
prev = fib
else:
# Is n closest to prev or to fib?
if n - prev < fib - n:
return False, prev
else:
return False, fib
# Test
for i in range(35):
print(i, nearest_fib(i))
输出
0 (True, 0)
1 (True, 1)
2 (True, 2)
3 (True, 3)
4 (False, 5)
5 (True, 5)
6 (False, 5)
7 (False, 8)
8 (True, 8)
9 (False, 8)
10 (False, 8)
11 (False, 13)
12 (False, 13)
13 (True, 13)
14 (False, 13)
15 (False, 13)
16 (False, 13)
17 (False, 21)
18 (False, 21)
19 (False, 21)
20 (False, 21)
21 (True, 21)
22 (False, 21)
23 (False, 21)
24 (False, 21)
25 (False, 21)
26 (False, 21)
27 (False, 21)
28 (False, 34)
29 (False, 34)
30 (False, 34)
31 (False, 34)
32 (False, 34)
33 (False, 34)
34 (True, 34)
更新
这里有一个更有效的方法,它使用 Binet's formula to first approximate y: F(y) = n. It then uses a pair of identities related to the matrix form(可以在 O(log(n)) 时间内计算 F(n))递归地找到最接近 n 的斐波那契数。递归非常快,因为它使用缓存来保存已经计算过的值。在没有缓存的情况下,该算法的速度与 Rockybilly 的速度大致相同。
from math import log, sqrt
def fast_fib(n, cache={0: 0, 1: 1}):
if n in cache:
return cache[n]
m = (n + 1) // 2
a, b = fast_fib(m - 1), fast_fib(m)
fib = a * a + b * b if n & 1 else (2 * a + b) * b
cache[n] = fib
return fib
logroot5 = log(5) / 2
logphi = log((1 + 5 ** 0.5) / 2)
def nearest_fib(n):
if n == 0:
return 0
# Approximate by inverting the large term of Binet's formula
y = int((log(n) + logroot5) / logphi)
lo = fast_fib(y)
hi = fast_fib(y + 1)
return lo if n - lo < hi - n else hi
for i in range(35):
print(i, nearest_fib(i))
输出
0 0
1 1
2 2
3 3
4 5
5 5
6 5
7 8
8 8
9 8
10 8
11 13
12 13
13 13
14 13
15 13
16 13
17 21
18 21
19 21
20 21
21 21
22 21
23 21
24 21
25 21
26 21
27 21
28 34
29 34
30 34
31 34
32 34
33 34
34 34
请注意,fast_fib
使用 default mutable argument 作为缓存,但这没关系,因为我们希望 缓存记住其以前的内容。
在我的速度测试中,默认的可变参数缓存比任何其他形式的缓存都快,但它的缺点是无法从函数外部清除缓存,并且如果您向函数添加缓存逻辑当您不想清除缓存时,清除它会影响大多数调用的性能。
更新
实际上可以从函数外部清除默认的可变参数缓存。我们可以通过函数的 .__default__
属性(或旧版本 Python 2 中的 .func_defaults
访问函数的默认参数;.__default__
在 Python 2.6 中有效,但在2.5).
例如,
d = fast_fib.__defaults__[0]
d.clear()
d.update({0: 0, 1: 1})
这里有一些代码(在 Python 2 和 Python 3 上运行)对为此问题提交的一些算法执行计时测试。 Rockybilly 与我的第一个版本非常相似,只是它避免了必须保存以前的值。我还使 OP 的 fibs
生成器更加紧凑。
Douglas 代码适用于小数,或者当参数实际上是斐波那契数时,但由于缓慢的逐一搜索。我已经能够通过避免重新计算各种数量来稍微优化它,但这对 运行 速度没有太大影响。
在这个版本中,我的 fast_fib()
函数使用了一个全局缓存,这样它就可以在测试之间被清除,从而使计时更加公平。
#!/usr/bin/env python3
""" Find the nearest Fibonacci number to a given integer
Test speeds of various algorithms
See
Written by PM 2Ring 2016.11.19
Incorporating code by Rockybilly and Douglas
"""
from __future__ import print_function, division
from math import log, sqrt
from time import time
def fibs():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
def nearest_fib_Rocky(n):
''' Find the nearest Fibonacci number to n '''
fibgen = fibs()
for fib in fibgen:
if fib == n:
return n
elif fib > n:
next_fib = next(fibgen)
return next_fib - fib if 2 * n < next_fib else fib
def nearest_fib_Doug(n):
a = 5 * n * n
if sqrt(a + 4)%1 == 0 or sqrt(a - 4)%1 == 0:
return n
c = 1
while True:
m = n + c
a = 5 * m * m
if sqrt(a + 4)%1 == 0 or sqrt(a - 4)%1 == 0:
return m
m = n - c
a = 5 * m * m
if sqrt(a + 4)%1 == 0 or sqrt(a - 4)%1 == 0:
return m
c += 1
cache={0: 0, 1: 1}
def fast_fib(n):
if n in cache:
return cache[n]
m = (n + 1) // 2
a, b = fast_fib(m - 1), fast_fib(m)
fib = a * a + b * b if n & 1 else (2 * a + b) * b
cache[n] = fib
return fib
logroot5 = log(5) / 2
logphi = log((1 + 5 ** 0.5) / 2)
def nearest_fib_PM2R(n):
if n == 0:
return 0
# Approximate by inverting the large term of Binet's formula
y = int((log(n) + logroot5) / logphi)
lo = fast_fib(y)
hi = fast_fib(y + 1)
return lo if n - lo < hi - n else hi
funcs = (
nearest_fib_PM2R,
nearest_fib_Rocky,
nearest_fib_Doug,
)
# Verify that all the functions return the same result
def verify(lo, hi):
for n in range(lo, hi):
a = [f(n) for f in funcs]
head, tail = a[0], a[1:]
if not all(head == u for u in tail):
print('Error:', n, a)
return False
else:
print('Ok')
return True
def time_test(lo, hi):
print('lo =', lo, 'hi =', hi)
for f in funcs:
start = time()
for n in range(lo, hi):
f(n)
t = time() - start
print('{0:18}: {1}'.format(f.__name__, t))
print()
verify(0, 1000)
cache={0: 0, 1: 1}
time_test(0, 1000)
funcs = funcs[:-1]
cache={0: 0, 1: 1}
time_test(1000, 50000)
典型输出
Ok
lo = 0 hi = 1000
nearest_fib_PM2R : 0.005465507507324219
nearest_fib_Rocky : 0.02432560920715332
nearest_fib_Doug : 0.45461463928222656
lo = 1000 hi = 50000
nearest_fib_PM2R : 0.26880311965942383
nearest_fib_Rocky : 1.266334056854248
这些时间是在旧的 2GHz 32 位机器上 运行 Python 3.6 在 Linux 上。 Python 2.6 给出了类似的时间。
FWIW,Rockybilly 和我的代码都可以轻松处理非常大的数字。这是 time_test(10**1000, 10**1000 + 1000)
的计时输出:
nearest_fib_PM2R : 0.011492252349853516
nearest_fib_Rocky : 7.556792497634888
为什么这个方法行之有效:
这是一种不需要预先计算的方法,因此在检查非常大的数字时性能等方面非常棒。
程序:
from math import *
n = int(input("Enter a number:"))
if sqrt(5*n**2+4)%1==0 or sqrt(5*n**2-4)%1==0:
print("Your number is a Fibonacci number!")
else:
print("Your number is not a Fibonacci number.")
c = 0
while 1:
c += 1
if sqrt(5*(n+c)**2+4)%1==0 or sqrt(5*(n+c)**2-4)%1==0:
print("%s is the closest Fibonacci number to your entry." % str(n+c))
break
if sqrt(5*(n-c)**2+4)%1==0 or sqrt(5*(n-c)**2-4)%1==0:
print("%s is the closest Fibonacci number to your entry." % str(n-c))
break
解释:
如果 (5*n^2 + 4) 或 (5*n^2 – 4) 是一个完全平方数,则 n 是一个斐波那契数。
计划Input/Output
Enter a number: 9999999999
Your number is not a Fibonacci number.
9999816735 is the closest Fibonacci number to your entry.
Enter a number: 9999816735
Your number is a Fibonacci number!