Загрузка данных


import sympy as sp

x = sp.symbols("x")
f_expr = 2 * sp.log(x) - x ** 2 + 5                     # уравнение f(x) = 0

SEGMENTS = [(0.01, 0.1), (2, 3)]                        # отрезки изоляции корней (по графику)
ROOTS_COUNT = 2                                         # сколько корней найти
EPSILON = 0.0001                                        # точность
PARTS = 1000                                            # на сколько частей делим отрезок (для min и max)

if ROOTS_COUNT > len(SEGMENTS):                         # ошибка, если корней запрошено больше, чем есть
    raise ValueError(f"В уравнении корней: {len(SEGMENTS)}, а запрошено {ROOTS_COUNT}")


f = sp.lambdify(x, f_expr, "math")                      # f(x)
f1 = sp.lambdify(x, sp.diff(f_expr, x), "math")         # точная производная f'(x)
f2 = sp.lambdify(x, sp.diff(f_expr, x, 2), "math")      # точная вторая производная f''(x)

for i in range(ROOTS_COUNT):                            # по одному отрезку на каждый корень
    A, B = SEGMENTS[i]                                  # границы отрезка
    points = [A + (B - A) * k / PARTS for k in range(PARTS + 1)]        # точки разбиения отрезка
    m1 = min(abs(f1(p)) for p in points)                # min |f'(x)|
    M2 = max(abs(f2(p)) for p in points)                # max |f''(x)|

    x_prev = A if f(A) * f2(A) > 0 else B               # начальная точка: где f(x) * f''(x) > 0
    iterations = 0                                      # счётчик итераций
    while True:
        x_new = x_prev - f(x_prev) / f1(x_prev)         # формула Ньютона
        iterations += 1
        if f(x_new) == 0:                               # x - точный корень
            break
        if M2 / (2 * m1) * (x_new - x_prev) ** 2 < EPSILON:     # оценка погрешности
            break
        x_prev = x_new                                  # запоминаем для следующего шага

    print(f"Корень {i + 1}: {x_new:.8f}, итераций: {iterations}")