Загрузка данных
import sympy as sp
x = sp.symbols("x")
f_expr = 2 * sp.log(x) - x ** 2 + 5
SEGMENTS = [(0.01, 0.1), (2, 3)] # отрезки изоляции корней (из графика)
ROOTS_COUNT = 2
EPSILON = 0.0001
PARTS = 1000
if ROOTS_COUNT > len(SEGMENTS):
raise ValueError(f"В уравнении корней: {len(SEGMENTS)}, а запрошено {ROOTS_COUNT}")
f = sp.lambdify(x, f_expr, "math")
f1 = sp.lambdify(x, sp.diff(f_expr, x), "math")
f2 = sp.lambdify(x, sp.diff(f_expr, x, 2), "math")
def min_max(g, A, B):
points = [A + (B - A) * k / PARTS for k in range(PARTS + 1)]
values = [abs(g(p)) for p in points]
return min(values), max(values)
def start_point(A, B): # конец отрезка, где f(x) * f''(x) > 0
if f(A) * f2(A) > 0:
return A, B
return B, A
def dichotomy(A, B):
left, right = A, B
value_left = f(left)
if value_left * f(right) > 0: # проверка знаков до цикла
return None
previous_x = None
iterations = 0
while True:
x_new = (left + right) / 2
value_x = f(x_new)
iterations += 1
if value_x == 0:
break
if previous_x is not None and abs(x_new - previous_x) < EPSILON:
break
if value_left * value_x < 0:
right = x_new
else:
left = x_new
value_left = value_x
previous_x = x_new
return x_new, iterations
def simple_iterations(A, B):
M1 = min_max(f1, A, B)[1]
lam = -1 / M1 if f1(A) > 0 else 1 / M1 # параметр lambda: -1/M1 при f' > 0, 1/M1 при f' < 0
phi = lambda t: t + lam * f(t) # x = phi(x) = x + lambda * f(x)
q = min_max(lambda t: 1 + lam * f1(t), A, B)[1] # q = max |phi'(x)| = max |1 + lambda * f'(x)|
if q >= 1: # при q >= 1 метод не сходится
return None
x_prev = (A + B) / 2
iterations = 0
while True:
x_new = phi(x_prev)
iterations += 1
if q / (1 - q) * abs(x_new - x_prev) < EPSILON:
break
x_prev = x_new
return x_new, iterations
def newton(A, B):
m1 = min_max(f1, A, B)[0]
M2 = min_max(f2, A, B)[1]
x_prev = start_point(A, B)[0]
iterations = 0
while True:
x_new = x_prev - f(x_prev) / f1(x_prev)
iterations += 1
if f(x_new) == 0:
break
if M2 / (2 * m1) * (x_new - x_prev) ** 2 < EPSILON:
break
x_prev = x_new
return x_new, iterations
def secant(A, B):
m1, M1 = min_max(f1, A, B)
start, other = start_point(A, B)
x_prev, x_cur = other, start
iterations = 0
while True:
x_new = x_cur - f(x_cur) * (x_cur - x_prev) / (f(x_cur) - f(x_prev))
iterations += 1
if f(x_new) == 0:
break
if (M1 - m1) / m1 * abs(x_new - x_cur) < EPSILON:
break
x_prev, x_cur = x_cur, x_new
return x_new, iterations
def chord(A, B):
m1, M1 = min_max(f1, A, B)
fixed, x_cur = start_point(A, B) # fixed - неподвижный конец хорды
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:
break
if (M1 - m1) / m1 * abs(x_new - x_cur) < EPSILON:
break
x_cur = x_new
return x_new, iterations
def show(name, result):
if result is None:
print(f" {name}: метод неприменим на этом отрезке")
else:
print(f" {name}: {result[0]:.8f}, итераций: {result[1]}")
for i in range(ROOTS_COUNT):
A, B = SEGMENTS[i]
print(f"Корень {i + 1}, отрезок [{A}; {B}]")
show("Дихотомия ", dichotomy(A, B))
show("Простые итерации", simple_iterations(A, B))
show("Ньютон ", newton(A, B))
show("Секущие ", secant(A, B))
show("Хорды ", chord(A, B))