Недавно, на таком простом примере вычисления чисел Фиббоначи
споткнулся о страшные тормоза:
fib 1 = 1
fib 2 = 1
fib n = fib (n-1) + fib (n-2)
Уже при n=35 это длительные задержки, при n=40 -- двухядерный ноутбук
прилично висит уже минуты.
Можно ли процесс ускорить? Наверняка это достаточно популярная тема,
особенно избитый пример с числами Фиббоначи. Ведь аналогичная задача в
императивном программировании, оформленная в виде цикла считается
мгновенно для указанных n!!
Тут дело не в функциональности языка и не в циклах против рекурсии, а
в том что используются абсолютно разные алгоритмы вычисления. Как на
императивном языке можно реализовать неэффективный алгоритм, так и на
функциональном - эффективный.
Вот эта версия будет быстро вычислять хоть миллиардное число Фибоначчи.
fib :: Int -> Int
fib = fst . fib2
fib2 :: Int -> (Int, Int)
fib2 0 = (1, 1)
fib2 1 = (1, 2)
fib2 n
| even n = c `seq` (a*a + b*b, c*c - a*a)
| otherwise = c `seq` (c*c - a*a, b*b + c*c)
where (a,b) = fib2 (n `div` 2 - 1)
c = a + b
>
> --
> Отправить сообщение в SPb HUG: spb...@googlegroups.com
> Отменить подписку: spbhug-un...@googlegroups.com
> Страница группы: http://groups.google.com/group/spbhug?hl=ru
--
Eugene Kirpichov
Senior Software Engineer,
Grid Dynamics http://www.griddynamics.com/
Великий Гугл (правда на нелюбимом английском) дал еще несколько
подходящих решений, мож кому тоже будет интересно:
http://www.cubbi.org/serious/fibonacci/haskell.html
http://www.haskell.org/haskellwiki/The_Fibonacci_sequence
http://en.literateprograms.org/Fibonacci_numbers_(Haskell)
Тогда, видимо, задать вопрос следовало иначе:
есть ли общие приемы писать рекурсивные функции быстрыми и где об этом
можно узнать?
(например, я хотел бы узнать что-то про "хвостовую рекурсию" и можно
ли ее применять в этом случае)
Ответ типа "руки кривые" как-то грустно звучит :(
On 7 окт, 12:06, Eugene Kirpichov <ekirpic...@gmail.com> wrote:
> 7 октября 2010 г. 8:59 пользователь nsk.coder <nsk.co...@gmail.com> написал:
См. напр. http://fprog.ru/2009/issue3/ , статья "Элементы
функциональных языков", глава "Хвостовой вызов".
> (например, я хотел бы узнать что-то про "хвостовую рекурсию" и можно
> ли ее применять в этом случае)
Проблема у примера с фибоначчи не в том, что рекурсия не хвостовая, а
в том, что она древовидная и экспоненциальная - куча всего лишний раз
пересчитывается. Это не имеет вообще никакого отношения к явлению
рекурсии как таковой, просто использован неудачный алгоритм.
http://www.haskell.org/pipermail/haskell-cafe/2010-October/084528.html и
дальше по треду.
* Dmitry Olshansky <olsha...@gmail.com> [2010-10-07 13:56:30+0400]
--
Roman I. Cheplyaka :: http://ro-che.info/
"Don't let school get in the way of your education." - Mark Twain