Как улучшить функцию? Написал программу для решения нелинейных уравнений, но решает только простые, при вводе мат.функций просто зависает, помогите

Рейтинг: 0Ответов: 1Опубликовано: 29.04.2023
from tkinter import *
import tkinter as tk
import math 
import matplotlib.pyplot as plt
import numpy as np

win = Tk()
f_entry = tk.Entry(win, width=50)
a_entry = tk.Entry(win, width=20)
b_entry = tk.Entry(win, width=20)
result_label_delenie = tk.Label(win, text='Root value: ')
err_label = tk.Label(win, text='', foreground="Red")


def init_gui():
    win.title('Нелинейные уравнения')
    win.geometry('500x500')

    f_label = tk.Label(win, text='Функция:')
    f_label.pack()
    f_entry.pack()

    a_label = tk.Label(win, text='Начальная точка')
    a_label.pack()
    a_entry.pack()

    b_label = tk.Label(win, text='Конечная точка')
    b_label.pack()
    b_entry.pack()

    err_label.pack()
    err_label.pack()
    
    calc_button = tk.Button(win, text='Calculate', command=button_handler)
    calc_button.pack()

    result_label_delenie.pack()
    return win


def chord_method(f, a, b, eps) -> float:
    # метод хорд
    fa, fb = f(a), f(b)
    iter = 0
    while abs(b - a) > eps:
        c = (a*fb - b*fa) / (fb - fa)
        fc = f(c)
        if fc == 0:
            return c
        elif fa*fc < 0:
            b, fb = c, fc
        else:
            a, fa = c, fc
        
    return (a + b) / 2


def tangent_method(f, dummy, x0, eps) -> float:
    # метод касательных
    f0 = f(x0)
    iter = 0
    df = lambda x: (f(x + eps) - f(x)) / eps
    while abs(f0) > eps:
        iter += 1
        x0 -= f0 / df(x0)
        f0 = f(x0)
        
        
    return x0


def bisection_method(f, a, b, eps) -> float:
    """
    Метод половинного деления для нахождения одного корня 
    """
    fa = f(a)
    fb = f(b)
    iter = 0 

    while (b - a) / 2 > eps:
        c = (a + b) / 2
        fc = f(c)
        iter += 1
        if abs(fc) < 0.1:
            return c
        elif fa * fc < 0:
            b = c
            fb = fc
        else:
            a = c
            fa = fc
            
        
def button_handler():
    try:
        f_str = f_entry.get()
        a = float(a_entry.get())
        b = float(b_entry.get())
    except:
        err_label.config(text='Ошибка')
        return
    
    if a > b:
        err_label.config(text='Ошибка')
        return
    elif len(f_str) == 0:
        err_label.config(text='Ошибка')
        return
    else:
        err_label.config(text='')
        
    func = lambda x: eval(f_str, {'__builtins__': None, 'x': x}, math.__dict__)
    
    result_label_delenie.config(text=solve_equation(func, a, b))
    plot_function(func, a, b)


def solve_equation(user_f, a, b, eps = 1e-6) -> str:
    results = []
    funcs = [('Метод касательных', tangent_method) 
          ,  ('Метод хорд', chord_method) 
          ,  ('Метод половинного деления', bisection_method)]
    
    for func in funcs:
        results.append(func[0] + ': ')
        try:
            results.append(str(func[1](user_f, a, b, eps)))
        except Exception as ex:
            results.append(str(ex))
        finally:
            results.append('\n')
        
    return ''.join(results)
    

def plot_function(f, a, b):
    x = np.linspace(a, b, 1000)
    y = f(x)
    plt.plot(x, y)
    
    ax = plt.gca()
      
    ax.axhline(y=0, color='k')   
    ax.axvline(x=0, color='k')
    
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title('График функции')
    plt.show()


    if __name__ == "__main__":
        win = init_gui()
        win.mainloop()

Ответы

▲ 0

Модуль math не поддерживает numpy.array поэтому нужно использовать функции из самой numpy, то есть заменить:

func = lambda x: eval(f_str, {'__builtins__': None, 'x': x}, math.__dict__)

на

func = lambda x: eval(f_str, {'__builtins__': None, 'x': x}, np.__dict__)