Python и SymPy: проверяем вычисления
Зачем компьютер
Интегралы — тема, где легко ошибиться в знаке или коэффициенте. Компьютер помогает тремя способами:
- строит графики — видно, что вы вообще считаете;
- считает численно — получаем число, с которым можно сравнить свой ответ;
- считает символьно — SymPy находит первообразные и проверяет преобразования.
Но компьютер не заменяет умения: чтобы понять, почему интеграл берётся, надо уметь считать руками. Используйте его как проверку, а не как решебник.
NumPy: численные расчёты
NumPy работает с массивами чисел. Функции np.sin, np.exp, np.log, np.sqrt применяются ко всему массиву сразу:
import numpy as np
import vis
x = np.linspace(0, np.pi, 9) # 9 равноотстоящих точек от 0 до π
print(np.round(np.sin(x), 3))
xx = np.linspace(-np.pi, np.pi, 300)
vis.line(xx, {"sin x": np.sin(xx), "sin²x": np.sin(xx)**2, "(1 − cos 2x)/2": (1 - np.cos(2*xx)) / 2 + 0.03},
title="Графики функций (третий сдвинут на 0,03, чтобы был виден)", xlabel="x")
Численно найти интеграл можно суммой прямоугольников или функцией np.trapz (метод трапеций):
import numpy as np
x = np.linspace(0, np.pi, 100001)
print("∫₀^π sin x dx ≈", np.trapz(np.sin(x), x))
x = np.linspace(0, 1, 100001)
print("∫₀¹ eˣ dx ≈", np.trapz(np.exp(x), x), " точно: e − 1 =", np.e - 1)
SymPy: символьные вычисления
SymPy работает с формулами, а не с числами. Сначала объявляем символы, затем строим выражения:
import sympy as sp
x = sp.symbols("x")
f = x * sp.exp(x)
F = sp.integrate(f, x) # неопределённый интеграл (без + C!)
print("∫ x eˣ dx =", F)
print("проверка: F' =", sp.simplify(sp.diff(F, x)))
print("∫₀¹ x eˣ dx =", sp.integrate(f, (x, 0, 1))) # определённый интеграл
print("∫₀^∞ e^(−x²) dx =", sp.integrate(sp.exp(-x**2), (x, 0, sp.oo)))
print("численно:", sp.N(sp.integrate(sp.sin(x) / x, (x, 0, 1)), 10))
Полезные функции:
| Функция | Что делает |
|---|---|
sp.diff(f, x) |
производная |
sp.integrate(f, x) |
первообразная (без +C) |
sp.integrate(f, (x, a, b)) |
определённый интеграл; sp.oo — бесконечность |
sp.simplify(e), sp.expand(e), sp.factor(e) |
упростить, раскрыть скобки, разложить на множители |
sp.apart(e) |
разложить дробь на простейшие |
e.subs(x, 2) |
подставить значение |
sp.limit(e, x, 0) |
предел |
sp.N(e) |
вычислить численно |
sp.pi, sp.E, sp.oo |
\pi, e, \infty |
Две особенности SymPy, о которых важно помнить:
log— натуральный логарифм, и в ответах SymPy обычно нет модуля:integrate(1/x, x)даётlog(x), хотя правильнее \ln|x| + C;- константу C SymPy не пишет — добавляйте её сами.
Главное правило: проверка дифференцированием
Первообразные одной функции могут выглядеть совершенно по-разному. Например, \int \sin x \cos x\,dx можно записать как \frac{\sin^2 x}{2}, как -\frac{\cos^2 x}{2} или как -\frac{\cos 2x}{4} — и всё это верно, потому что эти функции отличаются на константы.
import sympy as sp
x = sp.symbols("x")
answers = [sp.sin(x)**2 / 2, -sp.cos(x)**2 / 2, -sp.cos(2*x) / 4]
for F in answers:
print(f"F = {str(F):16} F' = {sp.simplify(sp.diff(F, x))}")
print("разности:", sp.simplify(answers[0] - answers[1]), ",", sp.simplify(answers[0] - answers[2]))
Все три производные одинаковы, а разности ответов — константы. Поэтому сравнивать ответ с задачником «по виду» бессмысленно: дифференцируйте. Так же проверяются ответы в этом курсе — численно, с точностью до константы.
Итог
- NumPy считает численно: графики, суммы,
np.trapz. - SymPy считает символьно:
diff,integrate,simplify,apart,limit; без +C и часто без модуля в логарифме. - Первообразную проверяют дифференцированием; разные по виду ответы могут отличаться лишь на константу.
Практика решено 0 из 5
Вы нашли первообразную F(x) для f(x). Как надёжнее всего проверить ответ?
SymPy выдал integrate(1/x, x) = log(x). Что важно помнить?
Проверка первообразной. Напишите функцию is_antiderivative(F, f, xs): она получает две функции Python
(F — кандидат в первообразные, f — подынтегральная функция) и список точек xs. Для каждой точки
посчитайте численную производную \frac{F(x + h) - F(x - h)}{2h} при h = 10^{-5} и сравните с f(x):
верните True, если во всех точках отличие меньше 10^{-4}.
Какие тесты проверяют код (1)
import math xs = [0.5, 1.0, 1.7, 2.3] assert is_antiderivative(lambda x: x**3 / 3, lambda x: x**2, xs) assert is_antiderivative(lambda x: -math.cos(x) + 5, math.sin, xs), "Константа не важна" assert not is_antiderivative(lambda x: x**3, lambda x: x**2, xs), "x³ — не первообразная x²" assert not is_antiderivative(lambda x: math.log(x), lambda x: 1 / x**2, xs)
def is_antiderivative(F, f, xs):
h = 1e-5
for x in xs:
d = (F(x + h) - F(x - h)) / (2 * h)
if abs(d - f(x)) >= 1e-4:
return False
return True
Интегрируем на SymPy. Напишите функцию antiderivative(expr_text): она получает строку с выражением
от x (например, "x*exp(x)"), превращает её в выражение SymPy (sp.sympify), находит первообразную
(sp.integrate) и возвращает её строкой (str(...)).
Какие тесты проверяют код (1)
import sympy as sp
x = sp.symbols("x")
for text in ["x**2", "x*exp(x)", "cos(x)**2", "1/(x**2 + 1)"]:
F = antiderivative(text)
assert isinstance(F, str), "Верните строку"
assert sp.simplify(sp.diff(sp.sympify(F), x) - sp.sympify(text)) == 0, f"Производная ответа для {text} не совпадает с ним"
import sympy as sp
def antiderivative(expr_text):
x = sp.symbols("x")
return str(sp.integrate(sp.sympify(expr_text), x))
Площадь численно. Напишите функцию area(f, a, b, n), которая приближает \int_a^b f(x)\,dx суммой
n средних прямоугольников: отрезок делится на n равных частей шириной h = \frac{b - a}{n}, высота
каждого прямоугольника — значение f в середине части. Можно использовать NumPy (f принимает массив).
Какие тесты проверяют код (1)
import numpy as np assert abs(area(lambda x: x**2, 0, 1, 1000) - 1/3) < 1e-6, "∫₀¹ x² dx = 1/3" assert abs(area(np.sin, 0, np.pi, 1000) - 2) < 1e-5, "∫₀^π sin x dx = 2" assert abs(area(lambda x: x, 0, 2, 1) - 2) < 1e-12, "Для линейной функции средние прямоугольники точны даже при n = 1" assert abs(area(lambda x: x**2, 0, 1, 2) - 0.3125) < 1e-12, "При n = 2 середины — 0.25 и 0.75"
import numpy as np
def area(f, a, b, n):
h = (b - a) / n
mids = a + h * (np.arange(n) + 0.5)
return float(np.sum(f(mids)) * h)
Войдите, чтобы отмечать пройденные уроки.