УДК 004.9
Б.Л. Файфель
ОБ ОДНОЙ ВОЗМОЖНОСТИ ВЫЧИСЛЕНИЯ ЧИСЕЛ ФИБОНАЧЧИ С ПОМОЩЬЮ ФОРМУЛЫ БИНЕ
Аннотация. В статье рассмотрен алгоритм прямого вычисления чисел Фибоначчи с использованием формулы Бине без привлечения арифметики с плавающей точкой за время O(log n). Приведена реализация метода на языке Питон.
Ключевые слова: числа Фибоначчи, формула Бине, язык Питон
B.L. Fayfel
A WAY TO CALCULATE FIBONACCI NUMBERS USING BINET'S FORMULA
Abstract. The article describes an algorithm for direct calculation of Fibonacci numbers using Binet's formula without the floating point arithmetic in O (log n) time. The Python programming language is applied to implement the given methodology.
Keywords: Fibonacci numbers, Binet's formula, Python
ВВЕДЕНИЕ
Как хорошо известно, числа Фибоначчи - это целочисленная последовательность, первые два члена которой равны единице, а каждый последующий равен сумме двух предыдущих. За 500 лет, прошедших с момента ввода этой последовательности в математический обиход, она основательно изучена. Открыто много интереснейших формул с участием чисел Фибоначчи. Но одной из «непреходящих» учебных задач является вычисление чисел Фибоначчи. Для этого придумано много способов: от прямой рекурсии, основанной на формуле
^п = F-n—1 + Fn—2,
до матричного метода, описанного, например, в книге Д. Кнута [1]. Большая часть этих подходов (кроме матричного метода Кнута) основаны на рекуррентных свойствах после-
довательности Фибоначчи и позволяют вычислить величину Fn в лучшем случае за время О(п). Матричный метод Кнута (использующий матричное возведение в степень) позволяет вычислить число Фибоначчи за логарифмическое время [2].
Особняком в этом ряду алгоритмов располагается формула Бине (известная еще Муавру), имеющая вид
Эта формула кажется, на первый взгляд, привлекательной, однако она содержит иррациональное число, которое при компьютерных вычислениях мы вынуждены представлять в форме числа с плавающей точкой (т. е. заменить бесконечную непериодическую дробь конечной).
Сказанное означает, что вычисления не будут точными; в них вносится погрешность ограничения. Автору однажды попалась на глаза публикация [3], в которой использовалась формула Бине для вычисления очень большого числа Фибоначчи, но реализация предполагала использование плавающей арифметики сверхвысокой разрядности (с тем чтобы нужное число полностью уместилось в мантиссу).
В настоящей статье описана совершенно другая схема использования формулы Бине, которая вообще не использует плавающую точку.
где а и Ь - целые числа. Представляется вполне очевидным, что это множество алгебраически замкнуто относительно операций обычного сложения и умножения:
Кроме того, ноль и единица принадлежат к рассматриваемому множеству триви-
ОПИСАНИЕ МЕТОДА
Рассмотрим множество чисел вида
х = а + * Ь,
(а + Ь^5) + (с + = ((а + с) + (Ь + (а + Ь^5)(с + = ((ас + 5 Ъй) + (ай + Ьс)^5).
Вполне естественно реализуется вычитание:
(а + Ь^5) - (с + = ((а - с) + (Ь -
Другими словами, рассматриваемое множество образует кольцо [4]. Теперь можно реализовать арифметику на множестве пар (a, b), в которой сложение, вычитание и умножение будут описываться формулами:
(а, Ь) + (с, d) = ((а + с), (b + d)),
(a, b) - (с, d) = ((а - с), (b - d)),
(а, Ь) * (с, d) = ((ас + 5bd), (ad + be)).
При этом будут соблюдаться все обычные аксиомы сложения и умножения. Таким образом, можно «благополучно забыть» про V5 и реализовать прямое вычисление по формуле Бине.
В результате числитель дроби будет представлять собой пару вида (0, г
Деление этого иррационального числа на дает искомый целый результат. Естественно, что в действительности делить не требуется, достаточно вычислить (используя описанную выше арифметику пар) два бинома
A = (J+®1 и В = (-±—^,
2п 2п '
и затем произвести вычитание. РЕАЛИЗАЦИЯ
В качестве языка реализации будет использован очень популярный язык Питон. В данном случае Питон хорош тем, что в него встроена арифметика целых неограниченной точности. Понятно, что алгоритм может быть реализован на любом языке, но наличие «под руками» неограниченной разрядности целых сильно облегчает задачу. Вот как выглядят нужные функции: def prod_pairs(a,b):
return (a[0] *b[0]+5*a[1] *b[1],a[0] *b[1]+a[1] *b[0]) def sub_pairs(a,b):
return (a[0]-b[0],a[1]-b[1]) def pow_pair(a,n): c=a
for _ in range(n-1): c=prod_pairs(c,a) return c def flb_bine(n):
x1=pow_pair((1,1),n)
x2=pow_pair((1,-1),n) z=sub_pairs(x1,x2) return z[1]//(2**n)
Можно ли ускорить этот код? Да, можно, если ускорить возведение в степень (аналогично тому, как это сделано в [2]). Для ускорения возведения в степень имеется стандартный подход, заключающийся в том, что для вычисления xn вычисляется цепочка x -> x2 -> x4 ->... ->x2k до тех пор, пока 2k<=n, а затем аналогичным образом вычисляется x(n-2k). Используя эту схему, можно переписать функцию возведения в степень: def pow_pair(a,n): if (n==1):
return a c=copy(a) k=1
while k*2<=n: if k<=n:
c=prod_pairs(c,c) k=k*2 p=n-k if p>=1:
tmp=pow_pair(a,p) return prod_pairs(tmp,c) else:
return c
Использование этого приема позволяет вычислять числа Фибоначчи за время, близкое к логарифмическому, по формуле Бине и без использования арифметики с плавающей точкой.
Ниже приведены результаты тестов, сравнивающие время вычисления чисел Фибоначчи простой итерацией: def flb_ite(n): c,p=0,1
for _ in range(n):
c,p=c+p,c return c
и кодом, использующим функцию fib_bine. Несмотря на очевидную простоту кода fib_ite, функция fib_bine показывает значительно лучшие результаты. Так, на компьютере автора четырехсоттысячное число Фибоначчи по описываемому алгоритму вычисляется примерно за 2 с, а прямыми итерациями - за 27 с.
На рисунке по горизонтальной оси откладывается номер рассчитываемого числа Фибоначчи, по вертикальной - время в секундах.
Сравнение производительности алгоритмов вычисления
ЗАКЛЮЧЕНИЕ
Цель, сформулированная во введении к настоящей статье, полностью достигнута -описанный метод вычисления чисел Фибоначчи по формуле Бине оказывается весьма быстрым и может быть легко реализован в любой среде разработки, поддерживающий целые числа неограниченной разрядности (Python, Lisp, Haskell). Метод не нуждается в арифметике с плавающей точкой.
СПИСОК ЛИТЕРАТУРЫ
1. Кнут Д. Искусство программирования на ЭВМ, Т. 1. Основные алгоритмы. М: Вильямс, 2017. 720 с.
2. N-е число Фибоначчи за O(log N). URL: https://habr.com/ru/post/148336/ Время доступа: 08/12/2021 12:10
3. Расчет миллионного числа Фибоначчи. URL: https://habr.com/ru/company/skillfactory /blog/555914/ Время доступа: 08/12/2021 12:15
4. Ленг С. Алгебра. М.: Наука, 1965. 431 c.
СВЕДЕНИЯ ОБ АВТОРЕ
Файфель Борис Леонидович -
кандидат физико-математических наук, доцент кафедры прикладных информационных технологий Саратовского государственного технического университета имени Гагарина Ю.А.
Boris L. Fayfel -
PhD (Physics and Mathematics), Associate Professor, Department of Applied Information Technologies, Yuri Gagarin State Technical University of Saratov
Статья поступила в редакцию 01.12.21, принята к опубликованию 17.12.21