Как найти корень уравнения за 5 шагов там, где бисекция тратит 30
ОП.10 Численные методы · Специальность 09.02.07 «Информационные системы и программирование»
Лекция 3 · 2 академических часа (90 минут)
На прошлой лекции мы научились находить корни методом бисекции. Он надёжный, как трактор, но медленный. Сегодня мы освоим «гоночные болиды» численных методов — метод хорд и метод Ньютона. Они в 5–10 раз быстрее и именно их используют в реальных инженерных пакетах, играх и финансовых системах.
Справедливый вопрос. Метод бисекции гарантированно находит корень. Зачем что-то ещё? Ответ простой: скорость.
Представьте, что вам нужно найти корень уравнения с точностью до 15 знаков после запятой (это стандартная точность double, с которой работают реальные программы).
| Метод | Число шагов | Время (примерно) |
|---|---|---|
| Бисекция | ~50 шагов | Мгновенно для одной задачи, но если вызывать миллион раз — уже секунды |
| Метод хорд | ~10 шагов | В 5 раз быстрее |
| Метод Ньютона | ~5 шагов | В 10 раз быстрее |
Главная мысль: метод бисекции — это «молоток». Он всегда работает, но медленно. Методы хорд и Ньютона — это «шуруповёрт»: быстрее и точнее, но требуют понимания, как с ним обращаться. Сегодня мы этому и научимся.
Прежде чем двинуться дальше, освежим базу из Лекции №2.
Найти такое значение x, при котором функция обращается в ноль:
f(x) = 0
Геометрически это точка, где график функции пересекает горизонтальную ось Ox.
Мы умеем локализовать корень — найти отрезок [a, b], на концах которого функция имеет разные знаки:
f(a) · f(b) < 0
По теореме Больцано — Коши это гарантирует, что внутри отрезка есть хотя бы один корень.
Важно: методы хорд и Ньютона — это методы уточнения. Они предполагают, что корень уже локализован на отрезке [a, b]. Мы не ищем корень с нуля — мы «дожимаем» его до нужной точности.
Бисекция смотрит только на знаки функции (плюс или минус). Ей безразлично, насколько круто график идёт вверх или вниз. А методы хорд и Ньютона используют саму форму графика — они «прицеливаются» в корень точнее.
Слово «хорда» знакомо из геометрии: это отрезок, соединяющий две точки кривой. Именно эту идею мы и используем.
Представьте, что вы стоите на двух холмах и натянули между ними верёвку. Верёвка — это прямая. Там, где верёвка пересекает уровень земли (ноль), — примерно и находится корень. Потом вы переезжаете на один из холмов, ближе к этому месту, и снова натягиваете верёвку. И так несколько раз.
У нас есть точки A(a, f(a)) и B(b, f(b)). Мы проводим через них прямую (хорду). Эта прямая пересекает ось Ox в некоторой точке c. Это и есть наше новое приближение корня.
Рисунок 1. Метод хорд: прямая через точки A и B пересекает ось Ox в точке c — новом приближении корня
Затем мы смотрим: знак f(c) совпадает со знаком f(a) или f(b)? Тот конец отрезка, с которым совпал знак, «отбрасываем» и заменяем на c. Отрезок сужается, и мы повторяем.
Откуда берётся формула? Это уравнение прямой, проходящей через две точки.
Прямая через точки A(a, f(a)) и B(b, f(b)) задаётся уравнением:
y − f(a) = (f(b) − f(a)) / (b − a) · (x − a)
Нам нужна точка, где эта прямая пересекает ось Ox, то есть где y = 0. Подставляем y = 0 и выражаем x:
c = a − f(a) · (b − a) / (f(b) − f(a))
Это и есть рабочая формула метода хорд. Она даёт новое приближение корня c.
Запомните: формула не требует производной! Только значения функции в двух точках. Это делает метод хорд проще метода Ньютона, хотя и чуть медленнее.
[a, b] и точность ε. Проверяем: f(a) · f(b) < 0.c по формуле.|f(c)| < ε или |b − a| < ε — корень найден, возвращаем c.f(a) · f(c) < 0 — корень в левой части: b = c.a = c.Найдём корень уравнения x³ − x − 1 = 0 на отрезке [1, 2]. Это классическое уравнение, у которого нет красивой формулы решения.
f(1) = 1³ − 1 − 1 = −1 (отрицательно)f(2) = 8 − 2 − 1 = 5 (положительно)f(1) · f(2) = −5 < 0 — корень есть, идём дальше.c = a − f(a) · (b − a) / (f(b) − f(a))
c = 1 − (−1) · (2 − 1) / (5 − (−1)) = 1 + 1/6 ≈ 1.1667
Считаем f(c) = f(1.1667) ≈ 1.588 − 1.1667 − 1 = −0.5787 (отрицательно).
f(a) = −1 и f(c) = −0.579 — оба отрицательны. Значит, корень в правой части, делаем a = c = 1.1667.
Новый отрезок: [1.1667, 2].
c = 1.1667 − (−0.5787) · (2 − 1.1667) / (5 − (−0.5787)) ≈ 1.2531
Считаем f(c) ≈ −0.285 (отрицательно). Снова a = c.
c ≈ 1.2531 − (−0.285) · (2 − 1.2531) / (5 − (−0.285)) ≈ 1.2934
Считаем f(c) ≈ −0.128. И так далее.
Видим: за 3 шага мы продвинулись с 1.1667 до 1.2934. Точный корень — около 1.3247. Продолжая так ещё несколько шагов, мы дойдём до 6–8 знаков точности примерно за 8–10 итераций.
Как и любой численный метод, метод хорд имеет условия сходимости. Хорошая новость: они не очень строгие.
f(x) непрерывна на отрезке [a, b].f(a) · f(b) < 0.f'(x) не обращается в ноль на отрезке (функция монотонна — не «разворачивается»).f''(x) сохраняет знак на отрезке (график не имеет перегибов внутри).Опасный случай: если на отрезке [a, b] есть несколько корней или функция немонотонна, метод хорд может «застрять» — он будет бесконечно сужать отрезок вокруг одного корня, но не того, который нам нужен, или вовсе остановится, не достигнув корня.
Метод хорд имеет линейную (почти суперлинейную) сходимость. Это значит, что число верных знаков растёт примерно на 1 за итерацию. Быстрее бисекции, но медленнее Ньютона.
Скорость в цифрах: для достижения точности 10⁻⁶ бисекции нужно ~20 шагов, а методу хорд — обычно 8–12 шагов. Для точности 10⁻¹⁵ — 50 и 20 шагов соответственно.
Сравните с бисекцией: код почти такой же, но формула середины заменена на формулу хорды.
def f(x):
"""Наша функция: x^3 - x - 1"""
return x**3 - x - 1
def chord_method(a, b, epsilon, max_iter=100):
"""Метод хорд для поиска корня на отрезке [a, b]"""
# Проверяем, что на концах разные знаки
if f(a) * f(b) >= 0:
print("Ошибка: f(a) и f(b) одного знака!")
return None
step = 0
print(f"{'Шаг':<5} {'a':<12} {'b':<12} {'c':<12} {'f(c)':<15}")
print("-" * 60)
while step < max_iter:
# Формула хорды
c = a - f(a) * (b - a) / (f(b) - f(a))
fc = f(c)
step += 1
print(f"{step:<5} {a:<12.8f} {b:<12.8f} {c:<12.8f} {fc:<15.2e}")
# Проверка на сходимость
if abs(fc) < epsilon or abs(b - a) < epsilon:
return c
# Сужаем отрезок
if f(a) * fc < 0:
b = c
else:
a = c
print("Достигнут лимит итераций!")
return (a + b) / 2
# Запуск
root = chord_method(1, 2, 1e-6)
print(f"\n🎯 Корень найден: x ≈ {root:.8f}")
print(f"Проверка: f(x) = {f(root):.2e}")
Шаг 1: a=1.00000000 b=2.00000000 c=1.16666667 f(c)=-5.79e-01
Шаг 2: a=1.16666667 b=2.00000000 c=1.25311203 f(c)=-2.85e-01
Шаг 3: a=1.25311203 b=2.00000000 c=1.29339903 f(c)=-1.28e-01
...
Шаг 10: a=1.32471795 b=2.00000000 c=1.32471796 f(c)=1.11e-16
🎯 Корень найден: x ≈ 1.32471796
Проверка: f(x) = 1.11e-16
Метод сошёлся за 10 шагов. Для сравнения, бисекция на том же отрезке с той же точностью потребовала бы около 20 шагов.
Метод хорд использует прямую, проходящую через две точки графика. А что если мы возьмём касательную к графику в одной точке? Интуиция подсказывает: касательная точнее «прилипает» к кривой, чем хорда.
Представьте, что вы спускаетесь с горы в тумане. Вы не видите всю гору, но чувствуете наклон под ногами. Логично идти в ту сторону, куда «скатывается» склон. Касательная — это именно направление склона в текущей точке.
У нас есть начальное приближение x₀. Проводим касательную к графику f(x) в точке (x₀, f(x₀)). Смотрим, где эта касательная пересекает ось Ox. Это точка x₁. Повторяем: касательная в x₁ даёт x₂, и так далее.
Рисунок 2. Метод Ньютона: касательная в точке x₀ пересекает ось Ox в точке x₁ — более точном приближении корня
Почему это быстрее? Касательная учитывает не только значение функции, но и её наклон (производную). Это как если бы вы ехали по навигатору, который знает не только «где вы», но и «куда движетесь».
Выведем формулу из геометрии. Касательная к графику f(x) в точке xₙ задаётся уравнением:
y − f(xₙ) = f'(xₙ) · (x − xₙ)
где f'(xₙ) — производная функции в точке xₙ (это и есть наклон касательной).
Нам нужна точка пересечения с осью Ox: подставляем y = 0 и выражаем x:
xₙ₊₁ = xₙ − f(xₙ) / f'(xₙ)
Это и есть итерационная формула метода Ньютона. Она также называется методом касательных или методом Ньютона — Рафсона.
Обратите внимание: в отличие от метода хорд, здесь нужна производная f'(x). Именно она даёт «турбоускорение». Но именно она же создаёт проблемы, если производная близка к нулю.
x₀ (обычно берём один из концов отрезка локализации).xₙ₊₁ = xₙ − f(xₙ) / f'(xₙ).|xₙ₊₁ − xₙ| < ε — корень найден, возвращаем xₙ₊₁.xₙ = xₙ₊₁ и повторяем.x³ − x − 1 = 0То же уравнение, что и для метода хорд. Сравним скорость.
f(x) = x³ − x − 1f'(x) = 3x² − 1x₀ = 1 (левый конец отрезка [1, 2], где f(1) = −1).x₁ = 1 − f(1) / f'(1) = 1 − (−1) / (3·1² − 1) = 1 + 1/2 = 1.5
Проверяем f(1.5) = 3.375 − 1.5 − 1 = 0.875. Уже ближе к нулю!
f(1.5) = 0.875, f'(1.5) = 3·2.25 − 1 = 5.75
x₂ = 1.5 − 0.875 / 5.75 ≈ 1.5 − 0.1522 = 1.3478
f(1.3478) ≈ 2.449 − 1.3478 − 1 = 0.1012.
f'(1.3478) ≈ 3·1.8165 − 1 ≈ 4.4496
x₃ = 1.3478 − 0.1012 / 4.4496 ≈ 1.3251
f(1.3251) ≈ 0.00188. Уже почти ноль!
x₄ ≈ 1.3247 — совпадает с точным корнем до 4 знаков!
Сравнение: за 4 шага мы получили 4–5 верных знаков. Метод хорд для этого же результата потребовал 6–7 шагов, а бисекция — около 15. Вот что значит «использовать производную»!
Это самое важное теоретическое понятие лекции. Разберёмся, что такое «квадратичная сходимость» и почему это круто.
Порядок сходимости — это число, показывающее, как быстро уменьшается ошибка от шага к шагу. Обозначается буквой p.
Пусть текущая ошибка равна 0.1 (1 верный знак после запятой).
| Шаг | Ошибка при p=1 | Ошибка при p=2 |
|---|---|---|
| 0 | 0.1 | 0.1 |
| 1 | 0.01 | 0.01 |
| 2 | 0.001 | 0.0001 |
| 3 | 0.0001 | 0.00000001 (10⁻⁸) |
| 4 | 0.00001 | 10⁻¹⁶ (предел точности double!) |
Впечатляющий факт: для достижения максимальной точности компьютера (15–16 знаков, double) бисекции нужно около 50 шагов, а методу Ньютона — всего 5–6. Именно поэтому Ньютон — стандарт в промышленных вычислениях.
Метод Ньютона — это мощный инструмент, но у него есть опасные режимы. Разберём, когда он работает, а когда ломается.
f(x) непрерывна и дифференцируема на отрезке.f'(x) ≠ 0 на отрезке (нет горизонтальных касательных).f''(x) не меняет знак на отрезке (нет точек перегиба).x₀ выбрано достаточно близко к корню.Проблема 1: производная близка к нулю. Если f'(xₙ) ≈ 0, мы делим на крошечное число, и следующая точка «улетает» в бесконечность.
Проблема 2: плохое начальное приближение. Если начать слишком далеко от корня, касательная может увести нас в совершенно другую часть графика (или в «яму», где производная ноль).
Проблема 3: циклическое поведение. В редких случаях метод может зациклиться: x₀ → x₁ → x₀ → x₁ → ... и никогда не сойтись.
Практическое правило (условие Фурье): если f''(x) и f(a) имеют один знак, то берём x₀ = a, иначе берём x₀ = b. Проще: выбираем тот конец отрезка, где функция и её вторая производная имеют одинаковый знак.
Надёжная стратегия в реальном коде: сделать 2–3 шага бисекции, чтобы получить хорошее начальное приближение, а затем «добить» корень методом Ньютона. Такая гибридная схема используется в scipy.optimize.newton и в промышленных инженерных пакетах.
Понадобится не только сама функция, но и её производная. Есть три способа её задать.
def f(x):
return x**3 - x - 1
def df(x):
"""Производная: 3x^2 - 1"""
return 3 * x**2 - 1
def newton_method(x0, epsilon, max_iter=50):
"""Метод Ньютона (касательных)"""
x = x0
print(f"{'Итерация':<10} {'x':<15} {'f(x)':<15} {'|dx|':<15}")
print("-" * 55)
for n in range(max_iter):
fx = f(x)
dfx = df(x)
# Проверка, что производная не близка к нулю
if abs(dfx) < 1e-12:
print("⚠️ Производная близка к нулю! Метод может разойтись.")
return None
x_new = x - fx / dfx
diff = abs(x_new - x)
print(f"{n+1:<10} {x_new:<15.10f} {f(x_new):<15.2e} {diff:<15.2e}")
if diff < epsilon:
return x_new
x = x_new
print("⚠️ Метод не сошёлся за заданное число итераций!")
return None
# Запуск
root = newton_method(1.0, 1e-10)
print(f"\n🎯 Корень найден: x ≈ {root:.12f}")
Итерация x f(x) |dx|
-------------------------------------------------------
1 1.5000000000 8.75e-01 5.00e-01
2 1.3478260870 1.01e-01 1.52e-01
3 1.3252003989 2.06e-03 2.26e-02
4 1.3247181739 8.31e-07 4.82e-04
5 1.3247179572 1.33e-13 2.17e-07
6 1.3247179572 0.00e+00 1.51e-14
🎯 Корень найден: x ≈ 1.324717957245
Обратите внимание: метод сошёлся за 6 итераций до точности 12 знаков после запятой. Это и есть магия квадратичной сходимости.
Иногда функция задана сложной формулой или вообще таблично. Символьно брать производную трудно. На помощь приходит численная производная.
Производная — это скорость изменения функции. Её можно приблизить разностью значений в двух близких точках:
f'(x) ≈ (f(x + h) − f(x − h)) / (2h)
где h — маленький шаг (например, 1e-7). Это центральная разность — она точнее, чем обычная.
def f(x):
return x**3 - x - 1
def df_numeric(x, h=1e-7):
"""Численная производная (центральная разность)"""
return (f(x + h) - f(x - h)) / (2 * h)
def newton_numeric(x0, epsilon, max_iter=50):
x = x0
for n in range(max_iter):
fx = f(x)
dfx = df_numeric(x)
if abs(dfx) < 1e-12:
return None
x_new = x - fx / dfx
if abs(x_new - x) < epsilon:
return x_new
x = x_new
return None
root = newton_numeric(1.0, 1e-10)
print(f"Корень: x ≈ {root:.12f}")
Плюс: не нужно вручную считать производную.
Минус: добавляется два лишних вызова функции на каждом шаге, и появляется небольшая погрешность из-за шага h. Но в 95% задач это не проблема.
У нас теперь полный арсенал. Пора расставить всё по местам.
| Критерий | Бисекция | Хорды | Ньютон |
|---|---|---|---|
| Что нужно знать о функции | Только знаки | Значения в двух точках | Значение и производную |
| Надёжность | ✅ Всегда сходится | ✅ Почти всегда | ⚠️ Только при хорошем старте |
| Порядок сходимости | Линейный (медленно) | Почти линейный (средне) | Квадратичный (очень быстро) |
| Шагов до 10⁻¹⁵ | ~50 | ~20 | ~5 |
| Сложность кода | Минимальная | Простая | Средняя (нужна производная) |
| Где используют | Когда нужна гарантия | Универсальный середняк | Стандарт в науке и ML |
Практический вывод: в реальных программах чаще всего делают «гибрид»: начинают с бисекции (надёжно), потом переключаются на Ньютона (быстро). Такой подход сочетает гарантию сходимости с высокой скоростью.
Один и тот же корень, одни и те же стартовые точки — но разные стратегии поиска. Смотрите, как по-разному методы приближаются к цели.
Рисунок 3. Три метода идут к одному корню разными путями. Бисекция — «шаг за шагом». Хорда — «прицельно-прямолинейно». Ньютон — «сразу почти в цель»
Наблюдение: обратите внимание, что касательная Ньютона (фиолетовая) почти сразу «приземляется» в окрестность корня, в то время как бисекция (синие точки) вынуждена пройти серию последовательных делений пополам.
Представьте, что вы пишете игру, где мяч летит с начальной скоростью под углом и нужно рассчитать, когда он упадёт на землю (или где пересечёт стену).
Мяч брошен с начальной скоростью v₀ = 20 м/с под углом 45°. Есть сопротивление воздуха, пропорциональное квадрату скорости. Уравнение высоты:
y(t) = v₀·sin(α)·t − (g/2)·t² − k·t³ = 0
где g = 9.81 м/с², k = 0.05 — коэффициент сопротивления.
Это кубическое уравнение. Формула Кардано существует, но она огромна и содержит комплексные числа даже при вещественных корнях. Проще — численно.
import math
def y(t):
v0, alpha, g, k = 20, math.radians(45), 9.81, 0.05
return v0 * math.sin(alpha) * t - (g/2) * t**2 - k * t**3
def dy(t):
v0, alpha, g, k = 20, math.radians(45), 9.81, 0.05
return v0 * math.sin(alpha) - g * t - 3 * k * t**2
# Локализация: где y меняет знак?
for t in [0, 1, 2, 3]:
print(f"t={t}: y={y(t):.3f}")
# y(2)>0, y(3)<0 → корень на [2, 3]
# Метод Ньютона, старт с t=2.5
t = 2.5
for _ in range(10):
t = t - y(t) / dy(t)
print(f"\nМяч упадёт через t ≈ {t:.4f} секунды")
Результат: мяч упадёт через t ≈ 2.7318 секунды. Метод Ньютона нашёл это за 4–5 итераций. Именно так работают физические движки Unity и Unreal Engine — только вместо метода Ньютона там часто используют его обобщение для систем уравнений.
Обучение нейросети — это поиск минимума функции потерь (error). А минимум функции — это точка, где её производная равна нулю.
Чтобы найти минимум функции L(w) (потери), нужно решить уравнение:
L'(w) = 0
Именно к этому уравнению и применяют метод Ньютона! В многомерном случае это обобщается: wₙ₊₁ = wₙ − H⁻¹·∇L(wₙ), где H — матрица вторых производных (гессиан).
Забавный факт: когда вы вызываете model.fit() в Keras или PyTorch, под капотом происходит миллион итераций поиска корня производной. Понимание метода Ньютона — это понимание того, как работает ваша нейросеть на самом деле.
В финансах есть понятие IRR (Internal Rate of Return — внутренняя норма доходности). Это ставка, при которой инвестиционный проект выходит в ноль (чистая приведённая стоимость равна нулю).
NPV(r) = Σ Cᵢ / (1 + r)ⁱ − C₀ = 0
где Cᵢ — денежные потоки, C₀ — начальные инвестиции, r — искомая ставка.
Это уравнение относительно r. Если платежей больше двух, оно превращается в полином высокой степени — аналитически решить невозможно.
Функция IRR() в Excel использует именно метод Ньютона (или его аналог). Когда вы вводите =IRR(A1:A20), Excel решает уравнение методом касательных за доли миллисекунды.
# Упрощённый расчёт IRR методом Ньютона
def npv(r, flows):
"""Чистая приведённая стоимость"""
return sum(cf / (1 + r)**i for i, cf in enumerate(flows))
def dnpv(r, flows):
"""Производная NPV по r"""
return sum(-i * cf / (1 + r)**(i+1) for i, cf in enumerate(flows))
def irr(flows, guess=0.1, eps=1e-9):
r = guess
for _ in range(100):
dr = npv(r, flows) / dnpv(r, flows)
r -= dr
if abs(dr) < eps:
return r
return None
# Пример: инвестиция -1000, возвраты 300, 400, 500
flows = [-1000, 300, 400, 500]
print(f"IRR ≈ {irr(flows)*100:.2f}%")
Результат: IRR ≈ 8.89%. Это значит, что проект окупается с доходностью 8.89% годовых. Именно так банки оценивают, давать ли вам кредит на бизнес.
В промышленном коде не используют «чистый» Ньютон. Слишком опасно — при плохом старте он разлетится. Делают так:
def hybrid_root(f, df, a, b, epsilon):
"""Гибрид: бисекция + Ньютон"""
# Шаг 1: несколько итераций бисекции
for _ in range(5):
c = (a + b) / 2
if f(a) * f(c) < 0:
b = c
else:
a = c
# Шаг 2: Ньютон из середины суженного отрезка
x = (a + b) / 2
for _ in range(50):
fx = f(x)
dfx = df(x)
if abs(dfx) < 1e-12:
break
x_new = x - fx / dfx
# Защита: если Ньютон вылетел за [a,b] — откат к середине
if not (a <= x_new <= b):
x_new = (a + x_new) / 2
if abs(x_new - x) < epsilon:
return x_new
x = x_new
return x
Именно так устроена функция scipy.optimize.root_scalar с методом 'brentq' или 'newton' в Python. Метод Брента — это комбинация бисекции, секущих и обратной квадратичной интерполяции. Он надёжен и быстр одновременно.
В реальной работе не пишут методы с нуля — используют scipy. Но знать, что внутри, необходимо, чтобы правильно выбирать инструмент.
from scipy.optimize import newton, root_scalar
import math
def f(x):
return x**3 - x - 1
def df(x):
return 3*x**2 - 1
# Метод Ньютона (нужна производная)
root1 = newton(f, x0=1.0, fprime=df, tol=1e-10)
print(f"newton: x = {root1:.12f}")
# Метод Ньютона с численной производной (без df)
root2 = newton(f, x0=1.0, tol=1e-10)
print(f"newton(num): x = {root2:.12f}")
# Гибридный метод Брента — золотой стандарт
result = root_scalar(f, bracket=[1, 2], method='brentq', xtol=1e-10)
print(f"brentq: x = {result.root:.12f}, шагов: {result.iterations}")
# Метод секущих (без производной, но с суперлинейной сходимостью)
result = root_scalar(f, x0=1.0, x1=2.0, method='secant', xtol=1e-10)
print(f"secant: x = {result.root:.12f}, шагов: {result.iterations}")
newton: x = 1.324717957245
newton(num): x = 1.324717957245
brentq: x = 1.324717957245, шагов: 8
secant: x = 1.324717957245, шагов: 9
Совет: для одиночного уравнения используйте root_scalar(..., method='brentq'). Для систем уравнений — scipy.optimize.fsolve или root. Для оптимизации (поиска минимума) — scipy.optimize.minimize.
В методе Ньютона f'(xₙ) может оказаться нулём (или очень близким к нулю числом). Программа либо упадёт, либо получит бесконечность.
# ❌ Плохо
x = x - f(x) / df(x)
# ✅ Хорошо
if abs(df(x)) < 1e-12:
print("Производная близка к нулю! Переключаюсь на бисекцию.")
# ... код бисекции ...
else:
x = x - f(x) / df(x)
Без ограничения на число итераций метод может крутиться вечно.
# ✅ Всегда ставьте лимит
for i in range(max_iter):
...
else:
print("Не сошлось за", max_iter, "итераций")
Если x₀ далеко от корня, Ньютон может «улететь». Всегда проверяйте, что x₀ лежит в пределах отрезка локализации.
Сравнивать f(x) == 0 — плохо. Используйте abs(f(x)) < eps.
Золотое правило: в любом итерационном методе всегда должно быть два условия остановки — по точности и по числу шагов. Первое даёт результат, второе защищает от зависания.
Проверьте себя — сможете ли ответить без подсказки?
xₙ₊₁ = xₙ − f(xₙ) / f'(xₙ) из уравнения касательной.Подсказка: если не можете ответить на вопрос 5 — вернитесь к слайду 10. Если не помните про сходимость — слайд 12.
Совет: попробуйте ответить на все вопросы вслух, как будто объясняете одногруппнику. Это лучший способ проверить понимание.
Если вы уверенно отвечаете на все 18 вопросов — вы готовы к практической работе. Если нет — просмотрите соответствующую лекцию и попробуйте снова.
scipy.optimize.newton и root_scalar.Понимать: почему методы с использованием производной быстрее, но опаснее, и как правильно комбинировать надёжность и скорость в реальном коде.
x³ − 2x − 5 = 0 на отрезке [2, 3] методом хорд с точностью 0.01. Сделать 3 шага, записать промежуточные значения.3x² − 2. Начать с x₀ = 2. Сделать 3 шага. Сравнить скорость с заданием 1.f(x) = e^x − 3x находит корень на отрезке [0, 1] тремя способами (бисекция, хорды, Ньютон) и выводит таблицу сравнения: метод, число итераций, найденный корень, время работы.scipy, проверить работу scipy.optimize.newton.Подсказка для задания 3: используйте time.perf_counter() вместо time.time() для более точного измерения времени.
Вы уже знаете, что метод Ньютона даёт квадратичную сходимость. Но почему? Вот красивое объяснение.
Пусть x* — точный корень, eₙ = xₙ − x* — текущая ошибка. Разложим f(x*) в ряд Тейлора в окрестности xₙ:
f(x*) = f(xₙ) + f'(xₙ)·(x* − xₙ) + (1/2)·f''(ξ)·(x* − xₙ)²
Но f(x*) = 0, а x* − xₙ = −eₙ. После преобразований (для тех, кто любит математику) получаем:
eₙ₊₁ ≈ (f''(x*) / (2·f'(x*))) · eₙ²
Новая ошибка eₙ₊₁ пропорциональна квадрату старой ошибки eₙ². Если ошибка была 10⁻³, следующая будет порядка 10⁻⁶, потом 10⁻¹², потом 10⁻²⁴ (уже за пределами точности компьютера).
Красота: именно множитель f''/(2f') показывает, что метод Ньютона работает тем лучше, чем «прямее» функция около корня (чем меньше вторая производная). У линейной функции f'' = 0, и метод Ньютона находит корень за 1 шаг — точно!
cos(x) − x = 0Это уравнение из Лекции №2. Тогда мы решали его бисекцией. Теперь сравним с Ньютоном.
f(x) = cos(x) − xf'(x) = −sin(x) − 1x₀ = 0.5 (внутри отрезка [0, 1]).| Шаг | xₙ | f(xₙ) | Ошибка |
|---|---|---|---|
| 0 | 0.5 | 0.3776 | 0.2391 |
| 1 | 0.7552 | −0.0268 | 0.0161 |
| 2 | 0.7391 | −0.0001 | 0.0001 |
| 3 | 0.7390851332 | 0.0000 | < 10⁻¹⁰ |
Обратите внимание на магию: ошибка на шаге 0 была 0.2391, на шаге 1 — 0.0161 (стала в 15 раз меньше), на шаге 2 — 0.0001 (в 160 раз меньше), на шаге 3 — < 10⁻¹⁰ (в миллион раз меньше). Это и есть квадратичная сходимость в действии.
Для сравнения: бисекция на том же отрезке до той же точности потратила бы около 25 шагов. Ньютон сделал за 3–4. Вот почему в стандартной функции scipy.optimize.root_scalar по умолчанию используют метод Брента (гибрид), а не бисекцию.
Мы освоили два «гоночных» метода поиска корней.
f'(x) ≈ 0. В реальном коде его комбинируют с бисекцией.scipy.optimize.newton и root_scalar.Главная мысль: в численных методах нет «лучшего» метода на все случаи. Есть метод, подходящий для вашей задачи. Бисекция — когда нужна гарантия. Хорды — когда нужен универсальный середняк. Ньютон — когда нужна максимальная скорость и есть производная.
Численные методы решения уравнений — это только начало. В курсе нас ждут:
Все эти темы опираются на то, что мы сегодня изучили: методы, сходимость, оценка точности. Так что не расслабляйтесь — впереди ещё много интересного!
Где это всё пригодится: в машинном обучении, компьютерной графике, финансовых расчётах, инженерии и научных исследованиях. Это не «математика ради математики», а инструменты, которые вы будете использовать всю карьеру.
«Используй форму графика — и получишь ответ в 10 раз быстрее.
Но всегда проверяй, что не сломался»
Методы хорд и Ньютона — это не «магия», а следствие простой идеи: если функция гладкая, её можно заменить прямой (хордой или касательной). Остаётся только правильно повторить это приближение несколько раз.
Спасибо за внимание!
До встречи на практической работе №3!
💡 Подсказка: используйте клавиши ← → на клавиатуре для переключения слайдов