web-dev-qa-db-fra.com

Séquence de Fibonacci en Ruby (récursivité)

J'essaie d'implémenter la fonction suivante, mais elle continue de me donner l'erreur stack level too deep (SystemStackError).

Des idées sur le problème?

def fibonacci( n )
    [ n ] if ( 0..1 ).include? n
    ( fibonacci( n - 1 ) + fibonacci( n - 2 ) ) if n > 1
end

puts fibonacci( 5 )
17
Maputo

Essaye ça

def fibonacci( n )
  return  n  if ( 0..1 ).include? n
  ( fibonacci( n - 1 ) + fibonacci( n - 2 ) )
end
puts fibonacci( 5 )
# => 5

consultez également cet article Fibonacci One-Liner

et plus .. https://web.archive.org/web/20120427224512/http://en.literateprograms.org/Fibonacci_numbers_ (Ruby)

Vous avez maintenant été bombardé de nombreuses solutions :)

concernant le problème dans votre solution

vous devez renvoyer n si son 0 ou 1

et add les deux derniers nombres ne sont pas le dernier et le suivant

Nouvelle version modifiée

def fibonacci( n )
    return  n  if n <= 1 
    fibonacci( n - 1 ) + fibonacci( n - 2 )
end 
puts fibonacci( 10 )
# => 55

Bon mot

def fibonacci(n)
   n <= 1 ? n :  fibonacci( n - 1 ) + fibonacci( n - 2 ) 
end
puts fibonacci( 10 )
# => 55
41
Pritesh Jain

Voici quelque chose que j'ai trouvé, je trouve cela plus simple.

def fib(n)
  n.times.each_with_object([0,1]) { |num, obj| obj << obj[-2] + obj[-1] }
end
fib(10)
18
Ruben Lopez

Ce n'est pas ainsi que vous calculez fibonacci, vous créez un énorme arbre récursif qui échouera pour des ns relativement petits. Je vous suggère de faire quelque chose comme ça:

def fib_r(a, b, n)
  n == 0 ? a : fib_r(b, a + b, n - 1)
end

def fib(n)
  fib_r(0, 1, n)
end

p (0..100).map{ |n| fib(n) }
11
Victor Moroz

linéaire

module Fib
  def self.compute(index)
    first, second = 0, 1
    index.times do
      first, second = second, first + second
    end
    first
  end
end

récursif avec mise en cache

module Fib
  @@mem = {}
  def self.compute(index)
    return index if index <= 1

    @@mem[index] ||= compute(index-1) + compute(index-2)
  end
end

Fermeture

module Fib
  def self.compute(index)
    f = fibonacci
    index.times { f.call }
    f.call
  end

  def self.fibonacci
    first, second = 1, 0
    Proc.new {
      first, second = second, first + second
      first
    }
  end
end

Aucune de ces solutions ne plantera votre système si vous appelez Fib.compute(256)

9
Dudo

Cette approche est rapide et utilise la mémorisation:

fib = Hash.new {|hash, key| hash[key] = key < 2 ? key : hash[key-1] + hash[key-2] }

fib[123] # => 22698374052006863956975682

Si vous vous demandez comment fonctionne cette initialisation de hachage, lisez ici:

https://Ruby-doc.org/core/Hash.html#method-c-new

9
Bijan
PHI = 1.6180339887498959
TAU = 0.5004471413430931

def fibonacci(n)
  (PHI**n + TAU).to_i
end

Vous n'avez pas besoin de récursivité.

7
iblue

La récursivité est très lente, voici un moyen plus rapide

a = []; a[0] = 1; a[1] = 1
i = 1
while i < 1000000
    a[i+1] = (a[i] + a[i-1])%1000000007
    i += 1
end

puts a[n]    

C'est O (1), mais vous pouvez utiliser l'exponentiation matricielle, voici l'une des implémentations de la mienne, mais elle est en Java => http://Pastebin.com/DgbekCJM , mais les exp. matricielles O(8logn). Voici un algorithme beaucoup plus rapide, appelé doublage rapide. Voici une implémentation Java Java de doublage rapide).

class FD {

    static int mod = 1000000007;

    static long fastDoubling(int n) {
        if(n <= 2) return 1;
        int k = n/2;
        long a = fastDoubling(k+1);
        long b = fastDoubling(k);
        if(n%2 == 1) return (a*a + b*b)%mod;
        else return (b*(2*a - b))%mod;
}

Pourtant, en utilisant la multiplication karatsuba, les deux exp matrice. et le doublage rapide devient beaucoup plus rapide, mais le doublage rapide bat exp matrice. par un facteur constant, eh bien je ne voulais pas être très complet ici. Mais j'ai récemment fait beaucoup de recherches sur les nombres de fibonacci et je veux que mes recherches soient utiles à tous ceux qui veulent apprendre,;).

6
user1621170

Cela peut vous aider.

def fib_upto(max)
  i1, i2 = 1, 1
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end

fib_upto(5) {|f| print f, " "}
4
Peter Prabu

Essayez ce oneliner

def fib (n)
    n == 0 || n == 1 ? n : fib(n-2) + fib(n-1)
end
print fib(16)

Sortie: 987

4
Yaron Lambers

je pense que c'est assez facile:

def fibo(n) a=0 b=1 for i in 0..n c=a+b print "#{c} " a=b b=c end

end
4
mizan rahman

Nous pouvons effectuer des séries de fibo de liste en utilisant l'algorithme ci-dessous

def fibo(n)
  n <= 2 ? 1 : fibo(n-1) + fibo(n-2)
end

Nous pouvons générer des séries comme ci-dessous

p (1..10).map{|x| fibo(x)}

ci-dessous est la sortie de cette

=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 
4
Rameshwar Vyevhare

solution en ligne la plus rapide et la plus petite:

fiby = ->(n, prev, i, count, selfy) {
  i < count ? (selfy.call n + prev, n, i + 1, count, selfy) : (puts n)
}
fiby.call 0, 1, 0, 1000, fiby

motif de selfie fonctionnel :)

3
Martynas
a = [1, 1]
while(a.length < max) do a << a.last(2).inject(:+) end

Cela remplira a avec la série. (Vous devrez considérer le cas lorsque max <2)

Si seul le nième élément est requis, vous pouvez utiliser Hash.new

fib = Hash.new {|hsh, i| hsh[i] = fib[i-2] + fib[i-1]}.update(0 => 0, 1 => 1)

fib[10]
# => 55 
2
Santhosh

Voici une solution plus concise qui crée une table de recherche:

fibonacci = Hash.new do |hash, key|
  if key <= 1
    hash[key] = key
  else
    hash[key] = hash[key - 1] + hash[key - 2]
  end
end

fibonacci[10]
# => 55 
fibonacci
# => {1=>1, 0=>0, 2=>1, 3=>2, 4=>3, 5=>5, 6=>8, 7=>13, 8=>21, 9=>34, 10=>55}
2

Une autre approche du calcul des nombres de fibonacci en profitant de la mémorisation:

$FIB_ARRAY = [0,1]
def fib(n)
  return n if $FIB_ARRAY.include? n
  ($FIB_ARRAY[n-1] ||= fib(n-1)) + ($FIB_ARRAY[n-2] ||= fib(n-2))
end

Cela garantit que chaque numéro de fibonacci n'est calculé qu'une seule fois, ce qui réduit considérablement le nombre d'appels à la méthode fib.

1

En voici un à Scala:

object Fib {
  def fib(n: Int) {
    var a = 1: Int
    var b = 0: Int
    var i = 0: Int
    var f = 0: Int
    while(i < n) {
      println(s"f(${i+1}) -> $f")
      f = a+b
      a = b
      b = f
      i += 1
    }
  }

  def main(args: Array[String]) {
    fib(10)
  }
}
1
farhany

Si vous voulez écrire l'algorithme fonctonal le plus rapide pour fib, il ne sera pas récursif. C'est l'une des rares fois où la manière fonctionnelle d'écrire une solution est plus lente. Parce que la pile se répète si vous utilisez quelque chose comme

fibonacci( n - 1 ) + fibonacci( n - 2 ) 

éventuellement n-1 et n-2 créeront le même nombre, donc des répétitions seront faites dans le calcul. Le moyen le plus rapide pour y parvenir est de manière itérative

def fib(num)
# first 5 in the sequence 0,1,1,2,3
fib1 = 1 #3
fib2 = 2 #4
i = 5 #start at 5 or 4 depending on wheather you want to include 0 as the first number
while i <= num
    temp = fib2
    fib2 = fib2 + fib1
    fib1 = temp
    i += 1
end
p fib2
end
fib(500)
1
Stuart G

C'est l'extrait que j'ai utilisé pour résoudre un défi de programmation chez URI Online Judge, j'espère que cela aide.

def fib(n)
  if n == 1
    puts 0
  else
    fib = [0,1]
    (n-2).times do
      fib << fib[-1] + fib[-2]
    end
    puts fib.join(' ')
  end
end

fib(45)

Une sortie

# => 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733
1
vhbsouza

Cela fait un moment, mais vous pouvez écrire une fonction d'une ligne assez élégante et simple:

def fib(n)
  n > 1 ? fib(n-1) + fib(n-2) : n
end
1
Alex Shelmire

Quelqu'un m'a demandé quelque chose de similaire aujourd'hui, mais il voulait obtenir un tableau avec une séquence de fibonacci pour un nombre donné. Par exemple,

fibo(5)  => [0, 1, 1, 2, 3, 5]
fibo(8)  => [0, 1, 1, 2, 3, 5, 8]
fibo(13) => [0, 1, 1, 2, 3, 5, 8, 13]
# And so on...

Voici ma solution. Il n'utilise pas la récursivité. Encore une solution si vous cherchez quelque chose de similaire: P

def fibo(n)
  seed = [0, 1]
  n.zero? ? [0] : seed.each{|i| i + seed[-1] > n ? seed : seed.Push(i + seed[-1])}
end
1
franciscodelgadodev

encore un autre ;)

def fib(n)
  f = Math.sqrt(5)
  ((((1+f)/2)**n - ((1-f)/2)**n)/f).to_i
end

sera également utile d'ajouter un peu de cache

def fibonacci
  @fibonacci ||= Hash.new {|h,k| h[k] = fib k }
end

nous serons donc en mesure de l'obtenir comme

fibonacci[3]  #=> 2
fibonacci[10] #=> 55
fibonacci[40] #=> 102334155
fibonacci     #=> {3=>2, 10=>55, 40=>102334155}
1
Mike Belyakov

1) Exemple, où l'élément max <100

def fibonachi_to(max_value)
  fib = [0, 1]
  loop do
    value = fib[-1] + fib[-2]
    break if value >= max_value
    fib << value
  end
  fib
end

puts fibonachi_to(100)

Production:

0
1
1
2
3
5
8
13
21
34
55
89

2) Exemple, où 10 éléments

def fibonachi_of(numbers)
  fib = [0, 1]
  (2..numbers-1).each { fib << fib[-1] + fib[-2] }
  fib
end

puts fibonachi_of(10)

Production:

0
1
1
2
3
5
8
13
21
34
1
shilovk

Je pense c'est la meilleure réponse , qui était une réponse d'un autre SO message posant une question similaire.

La réponse acceptée de PriteshJ ici utilise la récursion naïve de fibonacci, ce qui est bien, mais devient extrêmement lent une fois que vous avez dépassé le 40ème élément. C'est beaucoup plus rapide si vous mettez en cache/mémorisez les valeurs précédentes et les transmettez pendant que vous itérez récursivement.

1
Batkins

Rejoindre le train Fibonacci:

Régulier:

def fib(num)
  return num if (num < 2) else fib(num-1) + fib(num-2)
end

Avec mise en cache:

module Fib
  @fibs = [0,1]
  def self.calc(num)
    return num if (num < 2) else @fibs[num] ||= self.calc(num-1) + self.calc(num-2)
  end
end
1
Olian04