Задача про n-ое число Фибоначчи

от автора

Суть моего труда заключается в том, чтобы определить функцию для нахождения n-ого числа Фибоначчи с линейной сложностью поиска. Вот какие методы я попробовал:

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

# Тут я сделал через метод неопределённых коэффициентов, получилось примерно то что нужно, # но из-за необходимости использования больших степеней, на полиноме возникают ненужные неровности.  import numpy as np import matplotlib.pyplot as plt  n = 10 # Основной параметр  F1 = 0 F2 = 1 Y = [0, 1] for _ in range(n - 2):     A = F1 + F2     F1 = F2     F2 = A     Y.append(A)  X = np.array([i for i in range(1, n + 1)])  print(X) print(Y) print(len(X) == len(Y)) R = []  for i in range(n):   line = []   for j in range(n):     line.append(1*X[i] ** j)   R.append(line)  R = np.array(R) A = np.linalg.solve(R, Y) linsp  = np.linspace(X.min(), X.max()) f = np.poly1d(np.flip(A)) fun = [f(x) for x in linsp] plt.plot(linsp,fun); plt.scatter(X, Y, color='r', alpha=0.5); # Рисуем исходные точки #plt.plot(linsp,np.sin(2*linsp),'g--'); plt.grid(True)

[ 1 2 3 4 5 6 7 8 9 10]

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

True

Всё немного съезжает на больших степенях, возможно это получится починить, используя метод через производные, чтобы вышел более плавный и «гладкий» полином:

[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30]

[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]

True

Первый замер числа под номером 30:

267394558.0

3524578

Чем плох первый метод? У полинома образуются ненужные углы и неровности в областях между точками, на основе которых он был построен.

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

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

# Метод неопределённых коэффициентов import numpy as np import matplotlib.pyplot as plt  n = 13 # Основной параметр  F1 = 0 F2 = 1 Y = [0, 1] for _ in range(n - 2):     A = F1 + F2     F1 = F2     F2 = A     Y.append(A)  X = np.array([i for i in range(1, n + 1)])  print(X) print(Y) print(len(X) == len(Y)) R = []  for i in range(n):   line = []   for j in range(n):     line.append(1*X[i] ** j)   R.append(line)  R = np.array(R) A = np.linalg.solve(R, Y) linsp  = np.linspace(X.min(), X.max()) f = np.poly1d(np.flip(A)) fun = [f(x) for x in linsp] plt.plot(linsp,fun); plt.scatter(X, Y, color='r', alpha=0.5); # Рисуем исходные точки #plt.plot(linsp,np.sin(2*linsp),'g--'); plt.grid(True)  # Проверяю:  print("Второй замер числа под номером 30:") print(f(30).round(0))  # -5228112930.0  # Почему-то значение получилось отрицательным...

[ 1 2 3 4 5 6 7 8 9 10 11 12 13]

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]

True

Второй замер числа под номером 30:

-5228112930.0

Попробуем проанализировать график. Видно, что это экспонента.

Screenshot 2025-03-14 at 6.44.28 PM.png

общая формула для экспоненты

Подберём такие значения a и b чтобы все точки совпали:

import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit  n = 30  # Количество чисел Фибоначчи  # Генерация чисел Фибоначчи итеративным методом fibonacci = [0, 1] for i in range(2, n + 1):     fibonacci.append(fibonacci[i - 1] + fibonacci[i - 2])  x_data = np.arange(0, n + 1) y_data = np.array(fibonacci[:n+1])  # Определение экспоненциальной функции def exponential_func(x, a, b):     return a * np.exp(b * x)  # Подгонка параметров a и b с помощью curve_fit popt, pcov = curve_fit(exponential_func, x_data, y_data, p0=[1, 0.1])  # p0 - начальные значения для a и b  a_opt, b_opt = popt print("Оптимизированные параметры: a =", a_opt, "b =", b_opt)  # Генерация гладкой экспоненты для визуализации x_smooth = np.linspace(x_data.min(), x_data.max(), 500) y_smooth = exponential_func(x_smooth, a_opt, b_opt)  # Построение графика plt.plot(x_smooth, y_smooth, color='blue', label='Экспонента (аппроксимация)') plt.scatter(x_data, y_data, color='red', alpha=0.8, label='Точки Фибоначчи')  # Стилизация графика plt.grid(True) plt.xlabel('n') plt.ylabel('F(n)') plt.title('График экспоненты') plt.legend()  # Отображение графика plt.show() 

Оптимизированные параметры: a = 0.44721359546613776 b = 0.4812118250621712


ссылка на оригинал статьи https://habr.com/ru/articles/891820/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *