Суть моего труда заключается в том, чтобы определить функцию для нахождения 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

Попробуем проанализировать график. Видно, что это экспонента.
Подберём такие значения 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/
Добавить комментарий