Как написать последовательность Фибоначчи? - PullRequest
130 голосов
/ 30 января 2009

Я изначально неправильно запрограммировал программу. Вместо того, чтобы возвращать числа Фибоначчи между диапазонами (т.е. startNumber 1, endNumber 20 должен = только те числа между 1 и 20), я написал для программы, чтобы отобразить все числа Фибоначчи между диапазонами (то есть. StartNumber 1, endNumber 20 отображает = первые 20 чисел Фибоначчи). Я думал, что у меня был безошибочный код. Я тоже не понимаю, почему это происходит.

startNumber = int(raw_input("Enter the start number here "))
endNumber = int(raw_input("Enter the end number here "))

def fib(n):
    if n < 2:
        return n
    return fib(n-2) + fib(n-1)

print map(fib, range(startNumber, endNumber))

Кто-то указал в моей части II (которая была закрыта за дублирование - https://stackoverflow.com/questions/504193/how-to-write-the-fibonacci-sequence-in-python-part-ii)), что мне нужно передать startNumber и endNumber через генератор, используя цикл while. Может кто-нибудь указать мне направление о том, как это сделать? Любая помощь приветствуется.


Я учусь на программиста и столкнулся с небольшим количеством беспорядка. Меня просят написать программу, которая будет вычислять и отображать последовательность Фибоначчи по введенному пользователем начальному номеру и конечному номеру (т. Е. StartNumber = 20 endNumber = 100, и он будет отображать только числа между этим диапазоном). Хитрость заключается в том, чтобы использовать его включительно (что я не знаю, как это сделать в Python? - я предполагаю, что это означает использовать инклюзивный диапазон?).

То, что я имею до сих пор, это не настоящее кодирование, а:

  • Запись формулы последовательности Fib в бесконечное число
  • Отображение startNumber to endNumber только из последовательности Fib.

Я понятия не имею, с чего начать, и я прошу идеи или понимание того, как это написать. Я также пытался написать форумную последовательность Фибоначчи, но я тоже заблудился.

Ответы [ 43 ]

240 голосов
/ 31 января 2009

Существует много информации о последовательности Фибоначчи в Википедии и Вольфраме . Гораздо больше, чем вам может понадобиться. В любом случае, полезно узнать, как использовать эти ресурсы, чтобы найти (если возможно, быстро) то, что вам нужно.

Запись формулы последовательности Fib в бесконечное число

В математике это дается в рекурсивной форме:

fibonacci from wikipedia

В программировании бесконечный не существует. Вы можете использовать рекурсивную форму, переводя математическую форму непосредственно на ваш язык, например, в Python она становится такой:

def F(n):
    if n == 0: return 0
    elif n == 1: return 1
    else: return F(n-1)+F(n-2)

Попробуйте на вашем любимом языке и убедитесь, что эта форма требует много времени, когда n становится больше. Фактически это O (2 n ) во времени.

Перейдите на сайты, на которые я ссылался, и вы увидите это (на wolfram ):

Fibonacci Equation

Это довольно просто реализовать и очень, очень быстро вычислить в Python:

from math import sqrt
def F(n):
    return ((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5))

Другой способ сделать это - следовать определению (из wikipedia ):

Первый номер последовательности равен 0, второе число равно 1, и каждый последующее число равно сумме из двух предыдущих чисел Сама последовательность, давая последовательность 0, 1, 1, 2, 3, 5, 8 и т. Д.

Если ваш язык поддерживает итераторы, вы можете сделать что-то вроде:

def F():
    a,b = 0,1
    while True:
        yield a
        a, b = b, a + b

Отображение startNumber to endNumber только из последовательности Fib.

Как только вы знаете, как генерировать числа Фибоначчи, вам просто нужно циклически проходить через числа и проверять, соответствуют ли они заданным условиям.

Предположим, теперь вы написали f (n), который возвращает n-й член последовательности Фибоначчи (например, тот, что с sqrt (5))

На большинстве языков вы можете сделать что-то вроде:

def SubFib(startNumber, endNumber):
    n = 0
    cur = f(n)
    while cur <= endNumber:
        if startNumber <= cur:
            print cur
        n += 1
        cur = f(n)

В Python я бы использовал форму итератора и пошел бы:

def SubFib(startNumber, endNumber):
    for cur in F():
        if cur > endNumber: return
        if cur >= startNumber:
            yield cur

for i in SubFib(10, 200):
    print i

Мой совет научиться читать , что вам нужно. Project Euler (Google для него) научит вас так: P Удачи и веселья!

54 голосов
/ 20 июля 2014

Эффективный генератор Питона последовательности Фибоначчи

Я нашел этот вопрос, пытаясь получить самое короткое Pythonic-поколение этой последовательности (позже понял, что видел подобное в Python Enhancement Proposal ), и я не заметил, чтобы кто-нибудь еще подходил с моим конкретным решением (хотя верхний ответ становится близким, но все же менее элегантным), так что здесь, с комментариями, описывающими первую итерацию, потому что я думаю, что это может помочь читателям понять:

def fib():
    a, b = 0, 1
    while True:            # First iteration:
        yield a            # yield 0 to start with and then
        a, b = b, a + b    # a will now be 1, and b will also be 1, (0 + 1)

и использование:

for index, fibonacci_number in zip(range(10), fib()):
     print('{i:3}: {f:3}'.format(i=index, f=fibonacci_number))

печать:

  0:   0
  1:   1
  2:   1
  3:   2
  4:   3
  5:   5
  6:   8
  7:  13
  8:  21
  9:  34
 10:  55

(Для целей атрибуции я недавно заметил похожую реализацию в документации Python по модулям, даже используя переменные a и b, которые я сейчас вспоминаю, когда видел перед написанием этого ответа. Но я думаю, что этот ответ демонстрирует лучшее использование языка.)

Рекурсивно определенная реализация

Онлайн-энциклопедия целочисленных последовательностей рекурсивно определяет последовательность Фибоначчи как

F (n) = F (n-1) + F (n-2) с F (0) = 0 и F (1) = 1

Сжать это рекурсивное определение в Python можно следующим образом:

def rec_fib(n):
    '''inefficient recursive function as defined, returns Fibonacci number'''
    if n > 1:
        return rec_fib(n-1) + rec_fib(n-2)
    return n

Но это точное представление математического определения невероятно неэффективно для чисел, намного превышающих 30, потому что каждое вычисляемое число также должно рассчитываться для каждого числа ниже него. Вы можете продемонстрировать, насколько это медленно, используя следующее:

for i in range(40):
    print(i, rec_fib(i))

Memoized рекурсия для эффективности

Это можно запомнить, чтобы повысить скорость (в этом примере используется тот факт, что аргумент ключевого слова по умолчанию является одним и тем же объектом при каждом вызове функции, но обычно по этой причине вы не будете использовать изменяемый аргумент по умолчанию) :

def mem_fib(n, _cache={}):
    '''efficiently memoized recursive function, returns a Fibonacci number'''
    if n in _cache:
        return _cache[n]
    elif n > 1:
        return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
    return n

Вы обнаружите, что запомненная версия намного быстрее и быстро превысит вашу максимальную глубину рекурсии, прежде чем вы даже сможете подумать, чтобы встать на чашку кофе. Вы можете увидеть, насколько быстрее это визуально, выполнив это:

for i in range(40):
    print(i, mem_fib(i))

(Может показаться, что мы можем просто сделать следующее, но на самом деле это не позволяет нам использовать преимущества кэша, потому что он вызывает себя до вызова setdefault.)

def mem_fib(n, _cache={}):
    '''don't do this'''
    if n > 1:  
        return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
    return n

Рекурсивно определенный генератор:

Поскольку я изучал Haskell, я натолкнулся на эту реализацию в Haskell:

fib@(0:tfib) = 0:1: zipWith (+) fib tfib

Самое близкое, я думаю, что я могу добраться до этого в Python на данный момент:

from itertools import tee

def fib():
    yield 0
    yield 1
    # tee required, else with two fib()'s algorithm becomes quadratic
    f, tf = tee(fib()) 
    next(tf)
    for a, b in zip(f, tf):
        yield a + b

Это демонстрирует это:

[f for _, f in zip(range(999), fib())]

Впрочем, он может доходить только до предела рекурсии. Обычно 1000, тогда как версия на Haskell может доходить до сотен миллионов, хотя для этого используются все 8 ГБ памяти моего ноутбука:

> length $ take 100000000 fib 
100000000
24 голосов
/ 11 февраля 2014

Почему бы просто не сделать следующее?

x = [1,1]
for i in range(2, 10):  
    x.append(x[-1] + x[-2]) 
print(', '.join(str(y) for y in x))
20 голосов
/ 30 января 2009

Идея последовательности Фибоначчи показана в следующем коде Python:

def fib(n):
   if n == 1:
      return 1
   elif n == 0:   
      return 0            
   else:                      
      return fib(n-1) + fib(n-2)         

Это означает, что fib - это функция, которая может выполнять одно из трех действий. Он определяет fib (1) == 1, fib (0) == 0 и fib (n):

fib (n-1) + fib (n-2)

Где n - произвольное целое число. Это означает, что, например, fib (2) расширяется до следующей арифметики:

fib(2) = fib(1) + fib(0)
fib(1) = 1
fib(0) = 0
# Therefore by substitution:
fib(2) = 1 + 0
fib(2) = 1

Мы можем вычислить fib (3) аналогично арифметике, показанной ниже:

fib(3) = fib(2) + fib(1)
fib(2) = fib(1) + fib(0)
fib(2) = 1
fib(1) = 1
fib(0) = 0
# Therefore by substitution:
fib(3) = 1 + 1 + 0

Здесь важно понять, что fib (3) не может быть вычислен без вычисления fib (2), которое вычисляется путем знания определений fib (1) и fib (0). Наличие вызова самой функции, как это делает функция Фибоначчи, называется рекурсией, и это важная тема в программировании.

Это звучит как домашнее задание, поэтому я не собираюсь делать начальную / конечную часть для вас. Python - удивительно выразительный язык для этого, так что это должно иметь смысл, если вы понимаете математику и, надеюсь, научит вас рекурсии. Удачи!

Edit: одна потенциальная критика моего кода в том, что он не использует супер-удобную функцию Python yield, что делает функцию fib (n) намного короче. Мой пример немного более общий, хотя не так много языков вне Python на самом деле имеют выход.

12 голосов
/ 30 сентября 2014

Сложность времени:

Функция кэширования уменьшает обычный способ вычисления рядов Фибоначчи с O (2 ^ n) до O (n) , исключая повторы в рекурсивном дереве рядов Фибоначчи:

enter image description here

Код:

import sys

table = [0]*1000

def FastFib(n):
    if n<=1:
        return n
    else:
        if(table[n-1]==0):
            table[n-1] = FastFib(n-1)
        if(table[n-2]==0):
            table[n-2] = FastFib(n-2)
        table[n] = table[n-1] + table[n-2]
        return table[n]

def main():
    print('Enter a number : ')
    num = int(sys.stdin.readline())
    print(FastFib(num))

if __name__=='__main__':
    main()
8 голосов
/ 02 июня 2016

Это довольно эффективно, используя O (log n) основных арифметических операций.

def fib(n):
    return pow(2 << n, n + 1, (4 << 2*n) - (2 << n) - 1) % (2 << n)

В этой работе используется O (1) базовых арифметических операций, но размер промежуточных результатов велик и поэтому неэффективен.

def fib(n):
    return (4 << n*(3+n)) // ((4 << 2*n) - (2 << n) - 1) & ((2 << n) - 1)

Этот вычисляет X ^ n в кольце многочленов Z [X] / (X ^ 2 - X - 1) с использованием возведения в степень путем возведения в квадрат. Результатом этого вычисления является полином Fib (n) X + Fib (n-1), из которого можно прочитать n-е число Фибоначчи.

Опять же, это использует O (log n) арифметических операций и очень эффективно.

def mul(a, b):
        return a[0]*b[1]+a[1]*b[0]+a[0]*b[0], a[0]*b[0]+a[1]*b[1]

def fib(n):
        x, r = (1, 0), (0, 1)
        while n:
                if n & 1: r = mul(r, x)
                x = mul(x, x)
                n >>= 1
        return r[0]
6 голосов
/ 06 февраля 2014

канонический код Python для печати последовательности Фибоначчи:

a,b=1,1
while True:
  print a,
  a,b=b,a+b       # Could also use b=a+b;a=b-a

Для задачи «Вывести первое число Фибоначчи длиной более 1000 цифр»:

a,b=1,1
i=1
while len(str(a))<=1000:
  i=i+1
  a,b=b,a+b

print i,len(str(a)),a
3 голосов
/ 11 апреля 2013

использовать рекурсию:

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)
x=input('which fibonnaci do you want?')
print fib(x)
3 голосов
/ 26 января 2018

Мы знаем, что

enter image description here

И что n-я степень этой матрицы дает нам:

enter image description here

Таким образом, мы можем реализовать функцию, которая просто вычисляет мощность этой матрицы до n-й степени -1.

как все мы знаем, сила a ^ n равна

enter image description here

Таким образом, в конце функция Фибоначчи была бы O (n) ... ничем иным, как простой реализацией, если бы не тот факт, что мы также знаем, что x^n * x^n = x^2n и оценка x^n могут поэтому будет сделано со сложностью O (log n)

Вот моя реализация Фибоначчи с использованием языка быстрого программирования:

struct Mat {
    var m00: Int
    var m01: Int
    var m10: Int
    var m11: Int
}

func pow(m: Mat, n: Int) -> Mat {
    guard n > 1 else { return m }
    let temp = pow(m: m, n: n/2)

    var result = matMultiply(a: temp, b: temp)
    if n%2 != 0 {
        result = matMultiply(a: result, b: Mat(m00: 1, m01: 1, m10: 1, m11: 0))
    }
    return result
}

func matMultiply(a: Mat, b: Mat) -> Mat {
    let m00 = a.m00 * b.m00 + a.m01 * b.m10
    let m01 = a.m00 * b.m01 + a.m01 * b.m11
    let m10 = a.m10 * b.m00 + a.m11 * b.m10
    let m11 = a.m10 * b.m01 + a.m11 * b.m11

    return Mat(m00: m00, m01: m01, m10: m10, m11: m11)
}

func fibonacciFast(n: Int) -> Int {

    guard n > 0 else { return 0 }
    let m = Mat(m00: 1, m01: 1, m10: 1, m11: 0)

    return pow(m: m, n: n-1).m00
}

Это имеет сложность O (log n). Мы рассчитываем величину мощности Q с показателем n-1, а затем берем элемент m00, равный Fn + 1, который при показателе степени n-1 представляет собой именно n-е число Фибоначчи, которое мы хотели.

Если у вас есть функция быстрого Фибоначчи, вы можете перебирать начальный и конечный номер, чтобы получить интересующую вас часть последовательности Фибоначчи.

let sequence = (start...end).map(fibonacciFast)

Конечно, сначала выполните некоторую проверку начала и конца, чтобы убедиться, что они могут сформировать допустимый диапазон.

Я знаю, что этому вопросу 8 лет, но мне все равно было интересно отвечать. :)

2 голосов
/ 01 сентября 2016

это улучшение ответа Мэтью Генри:

def fib(n):
    a = 0
    b = 1
    for i in range(1,n+1):
            c = a + b
            print b
            a = b
            b = c

код должен печатать b вместо печати c

вывод: 1,1,2,3,5 ....

...