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}")