Решение алгебраических и трансцендентных уравнений численными методами
ОП.10 Численные методы · Специальность 09.02.07 «Информационные системы и программирование»
Объём: 2 академических часа
Сегодня мы переходим от теории к реальной разработке. Вы научитесь находить корни уравнений, которые невозможно решить по школьным формулам, используя язык программирования Python и мощные математические библиотеки.
В школе вы решали уравнения вида x² - 5x + 6 = 0 через дискриминант. Но в реальной IT-разработке 90% уравнений выглядят страшно: e^x - 3x = 0 или cos(x) - x = 0. Для них не существует готовых формул.
Главная цель практики: не просто «нажать кнопки», а понять, как компьютер ищет ответ там, где человек бессилен. Мы разобьём задачу на два этапа: сначала найдём, где примерно лежит корень, а потом уточним его до 6 знаков после запятой.
Прежде чем писать код, который будет «угадывать» число, нужно понять, где вообще искать. Графический метод — это самый наглядный способ.
Мы строим график функции y = f(x). Корень уравнения f(x) = 0 — это точка, где график пересекает горизонтальную ось Ox (ось абсцисс).
Библиотека matplotlib: в Python за графики отвечает библиотека matplotlib (от слов matlab и plotting). Она умеет рисовать линии, точки, сетки и подписи. Мы будем использовать её модуль pyplot.
Нам нужно найти небольшой отрезок [a, b], на котором график пересекает ось ровно один раз. Именно этот отрезок мы потом отдадим компьютеру для точных вычислений.
График — это хорошо, но компьютеру нужны числа. Здесь на помощь приходит фундаментальная теорема математического анализа.
Теорема Больцано — Коши (о промежуточном значении): если функция f(x) непрерывна на отрезке [a, b] и на концах отрезка принимает значения разных знаков (то есть одна положительная, а другая отрицательная), то внутри этого отрезка обязательно есть хотя бы один корень.
f(a) · f(b) < 0
Это условие означает, что функция «перепрыгнула» через ноль. Чтобы найти такой отрезок автоматически, мы используем метод перебора с шагом: берём точку x, считаем f(x), делаем маленький шаг вперёд, снова считаем. Если знак изменился — корень пойман!
Теперь, когда у нас есть отрезок [a, b], где спрятан корень, мы начинаем его «сжимать». Метод бисекции (от лат. bisectio — рассечение надвое) — самый надёжный алгоритм в численных методах.
Представьте, что вы ищете нужный дом на длинной улице. Вы делите улицу пополам и смотрите, в какой половине нужный дом. Потом делите эту половину пополам. И так далее, пока не упрётесь в нужную дверь.
c = (a + b) / 2.f(c).f(a) и f(c) разных знаков — корень в левой половине. Делаем b = c.a = c.|b - a| не станет меньше заданной точности ε (эпсилон).Плюс метода: он всегда сходится, если корень есть. Минус: сходится медленно (нужно много шагов).
Этот метод быстрее, но требует хитрости. Нам нужно переписать уравнение f(x) = 0 в виде x = φ(x) (читается «фи от икс»).
Пример: x³ - x - 1 = 0. Переносим x вправо: x³ = x + 1. Извлекаем кубический корень: x = ∛(x + 1). Теперь φ(x) = ∛(x + 1).
Берём любое начальное число x₀ (например, 1.0). Подставляем его в φ(x) и получаем x₁. Подставляем x₁ и получаем x₂. И так далее, пока числа не перестанут меняться.
xₙ₊₁ = φ(xₙ)
Условие сходимости: метод сработает, только если производная |φ'(x)| < 1 на нашем отрезке. Проще говоря, функция φ(x) должна быть «пологой». Если вы переписали уравнение неудачно, метод «разбежится» в бесконечность.
Преподаватель выдаёт вам один из четырёх вариантов. Для каждого варианта уже подготовлено удачное преобразование для метода итераций, чтобы вы не тратили время на алгебру.
| Вариант | Уравнение f(x) = 0 | Тип | Отрезок [a, b] | Функция φ(x) для итераций |
|---|---|---|---|---|
| 1 | x³ − x − 1 = 0 |
Алгебраическое | [1, 2] | x = ∛(x + 1) |
| 2 | cos(x) − x = 0 |
Трансцендентное | [0, 1] | x = cos(x) |
| 3 | e^x − 3x = 0 |
Трансцендентное | [0, 1] | x = e^x / 3 |
| 4 | x³ − 2x − 5 = 0 |
Алгебраическое | [2, 3] | x = ∛(2x + 5) |
Точность для всех вариантов: ε = 10⁻⁶ (в коде записывается как 1e-6). Это означает, что мы хотим, чтобы ошибка была меньше одной миллионной.
Постройте график функции f(x) на заданном отрезке и визуально убедитесь, что корень там есть.
Мы используем библиотеку numpy (для быстрых математических операций с массивами) и matplotlib.pyplot (для рисования).
import numpy as np
import matplotlib.pyplot as plt
# 1. Описываем нашу функцию
def f(x):
return x**3 - x - 1 # ЗАМЕНИТЕ НА СВОЙ ВАРИАНТ!
# 2. Создаём массив из 400 точек от 0 до 3
x = np.linspace(0, 3, 400)
y = f(x)
# 3. Рисуем график
plt.figure(figsize=(10, 6))
plt.plot(x, y, label='f(x)', color='blue', linewidth=2)
plt.axhline(0, color='black', linewidth=1) # Горизонтальная ось Ox
plt.axvline(0, color='black', linewidth=1) # Вертикальная ось Oy
plt.grid(True, alpha=0.3) # Сетка для удобства
plt.legend()
plt.title('График функции f(x)')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.show()
Что сделать: скопируйте код, замените формулу на свой вариант, запустите. Сделайте скриншот появившегося окна и вставьте в отчёт с подписью: «Рисунок 1. График функции для варианта N».
Теперь заставим компьютер найти отрезок [a, b] автоматически, используя теорему Больцано — Коши.
import math
def f(x):
return x**3 - x - 1 # ВАШ ВАРИАНТ
# Метод перебора с шагом 0.1
a = 0
h = 0.1
x = a
print("Таблица значений f(x):")
print(f"{'x':<10} {'f(x)':<15}")
print("-" * 25)
while x <= 3:
fx = f(x)
print(f"{x:<10.1f} {fx:<15.6f}")
# Проверяем смену знака с предыдущей точкой
if x > a and f(x - h) * fx < 0:
print(f"\n✅ Корень найден на отрезке [{x - h}, {x}]")
break
x += h
Как это работает: цикл while идёт по оси x с шагом h = 0.1. Мы умножаем значение функции в текущей точке на значение в предыдущей. Если произведение отрицательное (< 0), значит, знаки разные, и корень зажат между ними.
Реализуем алгоритм бисекции. Обратите внимание: мы используем abs(b - a) > epsilon вместо сравнения с нулём, чтобы избежать проблем с плавающей точкой (вспомните Лекцию 1 про 0.1 + 0.2).
def f(x):
return x**3 - x - 1 # ВАШ ВАРИАНТ
def bisection(a, b, epsilon):
step = 0
print(f"{'Шаг':<5} {'a':<12} {'b':<12} {'c':<12} {'f(c)':<15}")
print("-" * 60)
# Цикл работает, пока отрезок больше требуемой точности
while abs(b - a) > epsilon:
c = (a + b) / 2
fc = f(c)
step += 1
print(f"{step:<5} {a:<12.8f} {b:<12.8f} {c:<12.8f} {fc:<15.2e}")
if fc == 0:
return c # Идеальный случай (редко бывает с float)
elif f(a) * fc < 0:
b = c # Корень в левой половине
else:
a = c # Корень в правой половине
return (a + b) / 2
# Запуск
a, b = 1, 2 # Отрезок из Задания 2
epsilon = 1e-6
root = bisection(a, b, epsilon)
print(f"\n🎯 Корень найден: x ≈ {root:.8f}")
print(f"Проверка: f(x) = {f(root):.2e}")
Теперь используем функцию φ(x) из таблицы на Слайде 7. Не забудьте импортировать math для функций cos и exp.
import math
def phi(x):
# ВАШ ВАРИАНТ из таблицы! Например, для варианта 1:
return (x + 1) ** (1/3)
def simple_iteration(x0, epsilon, max_iter=100):
x = x0
print(f"{'Итерация':<10} {'x':<15} {'|x_new - x|':<15}")
print("-" * 40)
for n in range(max_iter):
x_new = phi(x)
diff = abs(x_new - x)
print(f"{n+1:<10} {x_new:<15.8f} {diff:<15.2e}")
# Условие остановки: изменение стало меньше точности
if diff < epsilon:
return x_new
x = x_new
print("⚠️ Метод не сошёлся!")
return None
# Запуск
x0 = 1.0 # Начальное приближение (берём середину отрезка [a, b])
epsilon = 1e-6
root = simple_iteration(x0, epsilon)
print(f"\n🎯 Корень найден: x ≈ {root:.8f}")
Параметр max_iter=100: это «аварийный тормоз». Если вы ошиблись в формуле φ(x) и метод разбегается, цикл остановится через 100 шагов, а не зависнет навсегда.
Инженер всегда выбирает лучший инструмент. Давайте измерим, какой метод быстрее.
import time
start = time.time() # Засекаем время ДО
# ... ваш код ...
end = time.time() # Засекаем время ПОСЛЕ
print(f"Время выполнения: {(end - start) * 1000:.2f} миллисекунд")
Заполните эту таблицу в своём отчёте на основе выводов консоли:
| Параметр | Метод бисекции | Метод итераций |
|---|---|---|
| Найденный корень | ||
| Число шагов/итераций | ||
| Значение f(x) в корне | ||
| Время работы (мс) |
Вывод: напишите 2-3 предложения. Какой метод потребовал меньше шагов? Почему, как вы думаете, бисекция надёжнее, но медленнее?
Отчёт — это лицо инженера. Следуйте этому чек-листу, чтобы работа была принята с первого раза:
matplotlib с подписью «Рисунок 1».Формат файла: PDF или DOCX. Имя файла: Фамилия_Практика2_ЧисленныеМетоды.pdf.
Опыт показывает, что студенты чаще всего спотыкаются об одни и те же грабли. Читайте внимательно!
φ(x). Проверьте таблицу на Слайде 7 или убедитесь, что |φ'(x)| < 1.max_iter в методе итераций или условие abs(b - a) > epsilon в бисекции никогда не станет ложным (например, из-за опечатки).if f(c) == 0: в бисекции. abs(f(c)) < epsilon.[a, b] выбран так, что f(a) и f(b) одного знака. f(a) * f(b) < 0 перед запуском.Золотое правило программиста: любой итерационный цикл должен иметь «аварийный выход» по числу шагов. Это спасёт вас от зависания программы во время сдачи работы преподавателю.
Вы научились находить корни уравнений,
которые невозможно решить по формуле.
Теперь вы понимаете, как работают инженерные калькуляторы, физические движки игр и финансовые алгоритмы. Сохраните отчёт и подготовьте его к сдаче.
Отличная работа! Вы сделали большой шаг в мире численных методов.
💡 Подсказка: используйте клавиши ← → на клавиатуре для переключения слайдов