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


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)|
    M1 = max(abs(f1(p)) for p in points)                # max |f'(x)|

    fixed, x_cur = (A, B) if f(A) * f2(A) > 0 else (B, A)   # fixed (неподвижный): где f(x) * f''(x) > 0
    iterations = 0                                      # счётчик итераций
    while True:
        x_new = x_cur - f(x_cur) * (fixed - x_cur) / (f(fixed) - f(x_cur))     # формула хорд
        iterations += 1
        if f(x_new) == 0:                               # x - точный корень
            break
        if (M1 - m1) / m1 * abs(x_new - x_cur) < EPSILON:       # оценка погрешности
            break
        x_cur = x_new                                   # сдвигаем подвижный конец

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