Явный метод Эйлера: геометрия касательной
Дифференциальное уравнение задаёт наклон решения в каждой точке плоскости. Метод Эйлера говорит простую вещь: раз мы знаем наклон прямо сейчас, давайте сделаем маленький прямой шажок в этом направлении — и повторим. Из этой наивной идеи вырастает весь численный анализ ОДУ.
Явный метод Эйлера — простейшая численная схема для задачи Коши
y' = f(t, y),y(t0) = y0, которая строит решение по формулеy_{n+1} = y_n + h·f(t_n, y_n), двигаясь вперёд маленькими прямыми отрезками вдоль касательной.
Зачем вообще численный метод
Большинство дифференциальных уравнений, которые встречаются на практике, не решаются в элементарных функциях. Даже безобидное на вид y' = t² + y² не имеет ответа в виде формулы. А ведь нам нужно знать, как ведёт себя температура остывающего тела, как падает заряд конденсатора, как меняется численность популяции. Если формулы нет — остаётся одно: считать решение по точкам, шаг за шагом, приближённо. Численные методы — это машина, которая превращает уравнение для производной в таблицу значений функции.
Метод Эйлера — самый первый кирпич этой машины. Он почти никогда не используется в продакшене из-за низкой точности, но именно с него начинают, потому что в нём видна суть всех остальных методов. Поймёте Эйлера — поймёте Рунге-Кутту, поймёте предиктор-корректор, поймёте, откуда берутся слова «порядок метода» и «устойчивость».
Геометрия касательной
Представьте поле направлений: в каждой точке плоскости (t, y) уравнение y' = f(t, y) подсказывает, под каким углом наклонена касательная к решению, проходящему через эту точку. Получается «причёска» из коротких чёрточек, и настоящее решение — это кривая, которая в каждой своей точке гладко вписана в эту причёску, всюду идёт вдоль чёрточек.
Мы стартуем из точки (t0, y0). Локально, на коротком отрезке, кривая почти совпадает со своей касательной. Наклон касательной нам известен — это f(t0, y0). Значит, можно пройти по касательной маленький горизонтальный шаг h вправо и подняться на h·f(t0, y0) по вертикали. Мы окажемся в новой точке (t0 + h, y0 + h·f(t0, y0)) — уже чуть в стороне от истинной кривой, но недалеко. Из этой новой точки повторяем тот же приём: смотрим наклон здесь и снова шагаем по касательной. Так шаг за шагом мы выкладываем ломаную, которая ползёт вдоль поля направлений.
y | .* точное решение | .*' | .*' o--o ломаная Эйлера | o-o' | o-o' касательная на каждом шаге | o-o' +---o-------------------------- t y0 t0 t0+h t0+2h
Видно главное: ломаная всё время отстаёт от настоящей кривой, когда та выпуклая. Мы берём наклон в начале шага, а на самом шаге решение успевает изогнуться — наклон уже не тот. Эта систематическая ошибка и есть цена простоты метода.
Как работает под капотом
Формально мы приближаем производную разностью вперёд. По определению y'(t) = lim (y(t+h) - y(t)) / h при h -> 0. Уберём предел и оставим конечное h: y'(t) ≈ (y(t+h) - y(t)) / h. Подставим сюда y'(t) = f(t, y(t)) и выразим следующее значение:
(y_{n+1} - y_n) / h ≈ f(t_n, y_n)
y_{n+1} ≈ y_n + h·f(t_n, y_n)
То же самое можно вывести через ряд Тейлора. Разложим точное решение в точке t_n + h:
y(t_n + h) = y(t_n) + h·y'(t_n) + (h²/2)·y''(ξ)
Метод Эйлера оставляет только первые два слагаемых: y_n + h·f(t_n, y_n). Отброшенный «хвост» начинается с (h²/2)·y'' — это и есть локальная ошибка одного шага, к ней мы вернёмся в следующем уроке.
Алгоритм предельно прост: завести переменные t и y, в цикле n раз пересчитать y по формуле и сдвинуть t на h. Никаких систем уравнений решать не надо — значение y_{n+1} выражено явно через уже известное y_n. Поэтому метод и называется явным.
Проверим на эталоне. Возьмём y' = y с условием y(0) = 1. Точное решение — экспонента math.exp(t). Это идеальный тест: ответ известен, и можно в каждой точке смотреть на ошибку. Заметьте красивый факт: для этого уравнения шаг Эйлера превращается в y_{n+1} = y_n + h·y_n = (1 + h)·y_n, то есть численное решение — это геометрическая прогрессия (1 + h)ⁿ, а точное — math.exp(t). При h = 0.1 получаем 1, 1.1, 1.21, 1.331, ... — степени числа 1.1.
import math
def euler(f, t0, y0, h, n):
"""Явный метод Эйлера: n шагов длины h из точки (t0, y0)."""
t, y = t0, y0
points = [(t, y)]
for _ in range(n):
y = y + h * f(t, y) # шаг по касательной
t = t + h
points.append((t, y))
return points
# Тестовая задача: y' = y, y(0) = 1, точное решение exp(t)
f = lambda t, y: y
result = euler(f, 0.0, 1.0, 0.1, 10)
print(f"{'t':>4} {'y_chisl':>10} {'y_tochn':>10} {'oshibka':>10}")
for t, y in result:
exact = math.exp(t)
print(f"{t:4.1f} {y:10.5f} {exact:10.5f} {exact - y:10.5f}")Вывод:
t y_chisl y_tochn oshibka 0.0 1.00000 1.00000 0.00000 0.1 1.10000 1.10517 0.00517 0.2 1.21000 1.22140 0.01140 0.3 1.33100 1.34986 0.01886 0.4 1.46410 1.49182 0.02772 0.5 1.61051 1.64872 0.03821 0.6 1.77156 1.82212 0.05056 0.7 1.94872 2.01375 0.06504 0.8 2.14359 2.22554 0.08195 0.9 2.35795 2.45960 0.10166 1.0 2.59374 2.71828 0.12454
Численное решение всё время идёт ниже точного и отстаёт всё сильнее: на t = 0.1 ошибка 0.005, а на t = 1.0 — уже 0.12. Это ровно то отставание выпуклой кривой, которое мы видели на схеме: экспонента изгибается вверх, а Эйлер каждый раз идёт по касательной, проведённой в начале шага, и не успевает за изгибом.
Частые ошибки
Путают t и y в аргументах f. Функция правой части всегда принимает два аргумента: текущее время и текущее значение. Даже если уравнение автономное (f не зависит от t, как y' = y), сигнатуру f(t, y) лучше держать единой — иначе при переходе к неавтономным задачам код сломается.
Сдвигают t до пересчёта y. Порядок строк важен: сначала используем старые t_n и y_n в формуле, и только потом увеличиваем t. Если поменять местами, наклон будет взят не в той точке.
Берут слишком большой шаг и удивляются мусору. Ошибка Эйлера прямо пропорциональна h. При h = 0.5 решение y' = y уползёт совсем далеко. Маленький h — точнее, но дороже по числу шагов. Этот компромисс — центральная тема всего раздела.
Считают, что больше шагов всегда лучше. До определённого предела — да, но при очень маленьком h начинает накапливаться ошибка округления чисел с плавающей точкой. Бесконечно уменьшать шаг бессмысленно.
- Метод Эйлера строит решение ОДУ как ломаную вдоль поля направлений: на каждом шаге идём по касательной, наклон которой даёт
f(t_n, y_n). - Формула явная:
y_{n+1} = y_n + h·f(t_n, y_n), следующее значение считается напрямую, без решения уравнений. - Выводится из разности вперёд или из обрезанного ряда Тейлора; отброшенный член
(h²/2)·y''— источник ошибки. - На выпуклых решениях ломаная систематически отстаёт; ошибка растёт с числом шагов и пропорциональна
h. - Простота метода — его главная учебная ценность: на нём видно устройство всех более точных схем.