Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何找到最近的斐波那契数列?_Python_Fibonacci - Fatal编程技术网

Python 如何找到最近的斐波那契数列?

Python 如何找到最近的斐波那契数列?,python,fibonacci,Python,Fibonacci,我的下一步是,如果输入不在斐波那契数列中,程序必须给出一个与输入最近的数列中的数字的输出。我不知道如何进行,有人能帮我吗 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:

我的下一步是,如果输入不在斐波那契数列中,程序必须给出一个与输入最近的数列中的数字的输出。我不知道如何进行,有人能帮我吗

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=fibs()
n=int(输入(“请输入一个数字:”)
对于fib in gen:
如果n==fib:
打印(“是的!您的数字是斐波那契数!”)
打破
如果fib>n:
打印(“不!您的数字不是斐波那契数字!”)
next_fib=next(gen)
上一个=下一个
如果n-prev

Edit:我第一次使用
gen.next()
来获取收益率的下一个值,但是我忘记了在Python 3中,它被重命名为
gen.next()
。请小心使用
next(gen)
是两个Python版本的预期用法。

如果您不介意进行额外的生成器调用,则不必保留以前的斐波那契

首先将生成器存储在变量中

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=fibs()
n=int(输入(“请输入一个数字:”)
对于fib in gen:
如果n==fib:
打印(“是的!您的数字是斐波那契数!”)
打破
如果fib>n:
打印(“不!您的数字不是斐波那契数字!”)
next_fib=next(gen)
上一个=下一个
如果n-prev

Edit:我第一次使用
gen.next()
来获取收益率的下一个值,但是我忘记了在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
n=int(输入(“请输入一个数字:”)
对于fib,itertools.izip中的下一个fib(fibs(),itertools.islice(fibs(),1,None)):
如果n==fib:
打印(“是的!您的数字是斐波那契数!”)
打破
如果next_fib>n:
如果n-fib

您可以使用
itertools.tee
对其进行一些优化。

您可以将
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
n=int(输入(“请输入一个数字:”)
对于fib,itertools.izip中的下一个fib(fibs(),itertools.islice(fibs(),1,None)):
如果n==fib:
打印(“是的!您的数字是斐波那契数!”)
打破
如果next_fib>n:
如果n-fib

您可以使用
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))

更新 这里有一个更有效的方法,它首先用来近似y:F(y)=n。然后,它使用一对与相关的恒等式(可以在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))
请注意,
fast\u fib
使用a作为缓存,但这里没有问题,因为我们希望缓存记住它以前的内容

在我的速度测试中,默认可变参数缓存比任何其他形式的缓存都快,但它的缺点是无法从函数外部清除缓存,如果向函数添加逻辑以清除缓存,则在不想清除缓存时,会影响大多数调用的性能

更新

实际上,可以从函数外部清除默认的可变参数缓存。我们可以通过函数的
。\uuuu default\uuuu
属性访问函数的默认参数(或者在Python2的旧版本中是
.func\u defaults
;在Python2.6中是
。\uuu default\uuuuuu
工作的,但在2.5中不是)

例如


下面是一些代码(在Python2和Python3上运行),它们对为这个问题提交的一些算法执行计时测试。Rockybilly的与我的第一个版本非常相似,只是它避免了保存以前的值。我还使OP的
fibs
生成器更加紧凑

Douglas的代码适用于小数值,或者当参数实际上是斐波那契数时,但对于大的非斐波那契数,由于逐个搜索的速度很慢,所以它变得非常慢。通过避免重新计算各种数量,我已经能够对其进行一些优化,但这对运行速度没有太大影响

在这个版本中,my
fast\u fib()
函数使用一个全局缓存,以便在测试之间清除它,从而使计时更加公平

#!/usr/bin/env python3

""" Find the nearest Fibonacci number to a given integer

    Test speeds of various algorithms

    See https://stackoverflow.com/questions/40682947/fibonacci-in-python

    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)
这些时间是在Linux上运行Python 3.6的旧2GHz 32位机器上进行的。Python2.6给出了类似的计时

FWIW,Rockybilly和我的代码都可以轻松处理非常大的数字。以下是
时间测试(10**1000,10**1000+1000)的定时输出


这里有一个使用生成器的简单方法,可以用来测试小数字

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))

更新 这里有一个更有效的方法,它首先用来近似y:F(y)=n。然后它使用pa
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
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
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!