Тестовый пример from math import * func = lambda x: x - cos(x) a1, b1 = 0.0, 1.0 e = 0.0001 def dihotomia_method(a, b, f): k=0 while b-a >= e: k+=1 c = (a+b)/2 if f(a) * f(c) < 0: a, b = a, c else: a, b = c, b return (a+b)/2, k import pylab as plb X = plb.arange(-1.0, 1.0, 0.1) Y = [func(x) for x in X] plb.plot(X, Y) plb.grid() print('root %s, iteration %s' % dihotomia_method(a1, b1, func)) Выход функции: root 0.739105224609375, iteration 14 Краткое описание методов 1) Метод половинного деления или дихотомии (дихотомия - сопоставленность или противопоставленность двух частей целого) при нахождении корня уравнения f(x)=0 состоит в делении пополам отрезка [a; b], где находится корень. Затем анализируется изменение знака функции на половинных отрезках, и одна из границ отрезка [a; b] переносится в его середину. Переносится та граница, со стороны которой функция на половине отрезка знака не меняет. Далее процесс повторяется. Итерации прекращаются при выполнении одного из условий: либо длина интервала [a; b] становится меньше заданной погрешности нахождения корня, либо функция попадает в полосу шума значение функции сравнимо с погрешностью расчетов. 2) В численном анализе метод Ньютона, также известный как метод Ньютона–Рафсона, названный в честь Исаака Ньютона и Джозефа Рафсона, представляет собой алгоритм поиска корней, который последовательно улучшает приближение к корням (или нулям) вещественнозначной функции. Самая базовая версия начинается с функции f с одной переменной, определенной для действительной переменной x, производной ф у н к ц и и f ' и начальной догадки x 0 для корня из f. Если функция удовлетворяет достаточным предположениям и начальное предположение близко, то 𝑥1 = 𝑥0 − 𝑓(𝑥0 ) 𝑓 ′ (𝑥0 ) является лучшим приближением к корню, чем x 0. Геометрически (x1, 0) является пересечением оси x и касательной графика f в точке (x0, f (x0)): то есть улучшенное предположение является единственным корнем линейного приближения в начальной точке. Процесс повторяется как 𝑥𝑛+1 = 𝑥𝑛 − 𝑓(𝑥𝑛 ) 𝑓 ′ (𝑥𝑛 ) до тех пор, пока не будет достигнуто достаточно точное значение. Этот алгоритм является первым в классе методов Хаусхолдера, за ним следует метод Галлея. Метод также может быть распространен на сложные функции и системы уравнений. 2 Решение простой задачи вручную выбранными методами. Метод половинного деления 3 Метод Ньютона: 4 Задание 1. Предложенное уравнение: ln(𝑎 − 𝑏𝑥 2 ) sin (𝑐 + 𝑑𝑥 2 ) Пример решения методом половинного деления (код скопирован из программы Jupyter Notebook): from math import sin, log func = lambda x: log(a-b*x**2)*sin(c+d*x**2) a=12 b=0.8 c=2.6 d=0.3 e=10**(-10) a1 = -2 b1 = 1 def dihotomia_method(a1, b1, f): k=0 while b1-a1>=e: k+=1 c1=(a1+b1)/2 if f(a1)*f(c1)<0: a1, b1 = a1, c1 else: a1, b1 = c1, b1 return (a1+b1)/2, k import pylab as py X = py.arange(a1, b1, 0.001) root = dihotomia_method(a1, b1, func)[0] py.plot([x for x in X], [func(x) for x in X]) py.plot(root, 0, 'o') ax = lab.gca() ax.set_xlabel('X') 5 ax.set_ylabel('f(x)') lab.title("График функции func(x) с корнем на заданном промежутке") py.grid(True) print('root =', dihotomia_method(a1, b1, func)[0],',','iteration =', dihotomia_method(a1, b1, func)[1]) Полученные результаты: ε – погрешность root – корень уравнения на заданном промежутке iteration – количество итераций, потребовавшихся для получения результата исходя из начальных условий 1 2 3 4 5 6 7 8 9 10 ε 0.01 0.001 0.0001 10*10^-4 10*10^-5 10*10^-6 10*10^-7 10*10^-8 10*10^-9 10*10^-10 root -1.3435821533203125 -1.3436279296875 -1.3435821533203125 -1.3436126708984375 -1.3436155319213867 -1.3436180353164673 -1.3436178117990494 -1.3436178201809525 -1.3436178198317066 -1.3436178196134279 iteration 9 12 15 15 19 22 25 29 32 35 Точкой на графике указан искомый корень уравнения в пределах интервала, который был заранее задан, т.к. на всем промежутке области определения функция имеет несколько корней. 6 Пример решения методом Ньютона (код скопирован из программы Jupyter Notebook): from sympy import * import numpy as nu import pylab as lab x = symbols('x') a=12 b=0.8 c=2.6 d=0.3 a1 = -1.5 e=10**(-10) f = log(a-b*x**2)*sin(c+d*x**2) func = lambda x: log(a-b*x**2)*sin(c+d*x**2) df = diff(log(a-b*x**2)*sin(c+d*x**2)) ddf = diff(df) def newton_method(a1, f, df, ddf): k=0 if f.replace(x, a1)*ddf.replace(x, a1)>0: err = 'Точка выбрана верно' while (f.replace(x, a1)*df.replace(x, a1))**2>=e**2: k+=1 c1 = -f.replace(x, a1)/df.replace(x, a1) + a1 a1 = c1 else: err = 'Функция не проходит в этой точке через ось абцисс. Попробуйте другую!' return a1, err, k root = newton_method(a1, f, df, ddf)[0] if newton_method(a1, f, df, ddf)[0] == a1: print(newton_method(a1, f, df, ddf)[1]) else: print(newton_method(a1, f, df, ddf)[1]) 7 print('root =', newton_method(a1, f, df, ddf)[0]) print('iteration =', newton_method(a1, f, df, ddf)[2]) X = nu.linspace(-2, 0, 100) Y = [func(x) for x in X] lab.plot(X, Y) lab.plot(root, 0, 'o') lab.grid(True) ax = lab.gca() ax.set_xlabel('X') ax.set_ylabel('f(x)') lab.title("График функции func(x) с корнем на заданном промежутке") Полученные результаты: 1 2 3 ε 10*10^-7 10*10^-9 10*10^-12 root -1.34361781967088 -1.34361781967088 -1.34361781965681 Выход функции: iteration 3 3 4 Точкой на графике указан искомый корень уравнения в пределах интервала, который был заранее задан, т.к. на всем промежутке области определения функция имеет несколько корней. 8 Выводы Методы, представленные в этой работе, для решения нелинейных уравнений, хорошо справляются с поставленной задачей, но в пределах определенных интервалов (точки старта) и погрешности. Наиболее быстрым и точным из рассмотренных, является метод Ньютона (метод касательных). Количество необходимых итераций для нахождения значения гораздо меньше по сравнению с методом дихотомии. Если найти среди ответов обоих методов значения, совпадающие по точности до 10 знака после запятой, то отношение количества итераций в методе половинного деления к методу касательных будет соответственно 35:3. Таким образом, метод Ньютона оказывается более востребованным при анализе функций по сравнению с методом дихотомии. 9