Avis de non-responsabilité: certains Haskell peut-être douteux.Haskell Fibonacci: Tail-récursif plus lent que l'approche de liste paresseux classique?
J'ai mis en 2 versions de Fibonacci, qui est linéaire et récursive (une variante claqua incl.), Et un autre en utilisant l'approche de la liste paresseuse classique:
{-# LANGUAGE BangPatterns #-}
-- Linear
fibLinear :: Int -> Integer
fibLinear 0 = 0
fibLinear 1 = 1
fibLinear x = fibLin' 2 1 2
where
fibLin' i y z | i == x = y
fibLin' i y z = fibLin' (i+1) z (z+y)
-- Linear banged
fibLinearBang :: Int -> Integer
fibLinearBang 0 = 0
fibLinearBang 1 = 1
fibLinearBang x = fibLin' 2 1 2
where
fibLin' (!i) (!y) (!z) | i == x = y
fibLin' (!i) (!y) (!z) = fibLin' (i+1) z (z+y)
-- Haskeller classic lazy
fibClassic :: Int -> Integer
fibClassic n = fib' !! n
where fib' = 0:1:zipWith (+) fib' (tail fib')
Lorsque vous utilisez criterion à benchmark il (code), je reçois des résultats un peu intuitifs: Fib 30 prend 443,0 ns pour fibLinear
et 279,5 ns pour fibLinearBang
, contre 73,51 ns pour fibClassic
. C'est étrange parce que je pense que fibLinear
& fibLinearBang
pourrait être optimisé en quelque chose comme une boucle ou un saut.
Ma seule estimation est peut-être fib'
dans fibClassic
est memoised comme une liste constante malgré être dans une définition de fonction afin que les invocations ultérieures de la fonction réutiliser la même liste pour la recherche. Est-ce que quelqu'un peut me donner une explication définitive pour mes résultats de référence?
Pour ceux qui sont intéressés, j'ai mis le projet sur Github.
Je voudrais essayer de rendre tout l'argument de 'fibLin'' strict et de nouveau l'indice de référence. Vous pouvez le faire, par exemple en utilisant 'fibLin '(! _) (! _) (! _) | ... 'dans le premier cas, et permettant l'extension relative' BangPatterns'. – chi
Quel est votre niveau d'optimisation? La récursivité de queue ne fonctionne que comme une performance de boucle quand elle est stricte et GHC pourrait seulement rendre votre code strict à certains niveaux d'optimisation. La version paresseuse n'est définitivement pas mémo et je ne sais pas à quel point cela peut aider (vous n'avez pas besoin de recalculer le début de la liste, mais vous devez encore la parcourir et le calcul ne prend pas beaucoup de temps). C'est juste relativement rapide par défaut. – sepp2k
Aussi pourquoi 'fibLin 'produit-il un tuple? Je ne vous vois jamais utiliser le deuxième élément. – sepp2k