Как сделать методы точнее? Python

Рейтинг: 0Ответов: 3Опубликовано: 04.05.2023

Написал вот такую прогу которая решает функцию разными методами

import math
def f(x):
    return math.pow(math.log(x), 4.5) # возведение натурального логарифма от x в степень 4,5

a = 2 # отрезок [2;4]
b = 4
exact_value = 0.3077347286 # значение интеграла, найденное с помощью формулы Ньютона-Лейбница

# метод Ньютона-Котеса
def newton_cotes(a, b, n):
    h = (b - a) / n # шаг интегрирования
    x = [a + i * h for i in range(n+1)] # список значений аргумента x
    y = [f(x_i) for x_i in x] # список значений функции f(x) в точках из списка x
    integral = 0
    for i in range(n):
        integral += (y[i] + y[i+1]) / 2 * h
    return integral
# метод прямоугольников
def rectangle(a, b, n):
    h = (b - a) / n # шаг интегрирования
    x = [a + i * h for i in range(n)] # список значений аргумента x
    y = [f((x[i]+x[i])/2) for i in range(n)] # список значений функции f(x) в точках из списка x
    integral = h * sum(y)
    return integral
# метод трапеций
def trapezoid(a, b, n):
    h = (b - a) / n # шаг интегрирования
    x = [a + i * h for i in range(n+1)] # список значений аргумента x
    y = [f(x_i) for x_i in x] # список значений функции f(x) в точках из списка x
    integral = h/2 * (y[0] + 2 * sum(y[1:-1]) + y[-1])
    return integral
# метод Симпсона
def simpson(a, b, n):
    h = (b - a) / n # шаг интегрирования
    x = [a + i * h for i in range(n+1)] # список значений аргумента x
    y = [f(x_i) for x_i in x] # список значений функции f(x) в точках из списка x
    integral = h/3 * (y[0] + 4 * sum(y[1:-1:2]) + 2 * sum(y[2:-2:2]) + y[-1])
    return integral

def simpsonn(f, a, b, n):
    h= (b - a) / n
    k=0.0
    x=a + h
    for i in range(1,n/2 + 1):
        k += 4*f(x)
        x += 2*h
    x = a + 2*h
    for i in range(1,n/2):
        k += 2*f(x)
        x += 2*h
    return (h/3)*(f(a)+f(b)+k)

n = 4

# метод Ньютона-Котеса
integral_nc = newton_cotes(a, b, n) # вычисление приближённого значения определённого интервала методом Ньютона-Котеса на интервалие [a, b] с использованием n интервалов
abs_error_nc = abs(exact_value - integral_nc) # вычисление абсолютной ошибки между точным и приближённым значением
rel_error_nc = abs_error_nc / exact_value # вычисление относительной погрешности путём деления абсолютной ошибки на точное значение
# метод прямоугольников
integral_rect = rectangle(a, b, n) # вычисление приближённого значения определённого интервала методом прямоугольника на интервалие [a, b] с использованием n интервалов
abs_error_rect = abs(exact_value - integral_rect) # вычисление абсолютной ошибки между точным и приближённым значением
rel_error_rect = abs_error_rect / exact_value # вычисление относительной погрешности путём деления абсолютной ошибки на точное значение
# метод трапеций
integral_trap = trapezoid(a, b, n) # вычисление приближённого значения определённого интервала методом трапеции на интервалие [a, b] с использованием n интервалов
abs_error_trap = abs(exact_value - integral_trap) # вычисление абсолютной ошибки между точным и приближённым значением
rel_error_trap = abs_error_trap / exact_value # вычисление относительной погрешности путём деления абсолютной ошибки на точное значение
# метод Симпсона
integral_simp = simpson(a, b, n) # вычисление приближённого значения определённого интервала методом Симпсона на интервалие [a, b] с использованием n интервалов
abs_error_simp = abs(exact_value - integral_simp) # вычисление абсолютной ошибки между точным и приближённым значением
rel_error_simp = abs_error_simp / exact_value # вычисление относительной погрешности путём деления абсолютной ошибки на точное значение
# вывод результатов
print("Метод Ньютона-Котеса:")
print("Приближенное значение интеграла:", round(integral_nc, 8)) # round(integral_nc, 8) - округление до 8 символов после запятой
print("Абсолютная погрешность:", round(abs_error_nc, 8))
print("Относительная погрешность:", round(rel_error_nc, 8))
print()
print("Метод прямоугольников:")
print("Приближенное значение интеграла:", round(integral_rect, 8))
print("Абсолютная погрешность:", round(abs_error_rect, 8))
print("Относительная погрешность:", round(rel_error_rect, 8))
print()
print("Метод трапеций:")
print("Приближенное значение интеграла:", round(integral_trap, 8))
print("Абсолютная погрешность:", round(abs_error_trap, 8))
print("Относительная погрешность:", round(rel_error_trap, 8))
print()
print("Метод Симпсона:")
print("Приближенное значение интеграла:", round(integral_simp, 8))
print("Абсолютная погрешность:", round(abs_error_simp, 8))
print("Относительная погрешность:", round(rel_error_simp, 8))

Но когда показал преподу код, он сказал что вычисления и погрешности должны быть точнее, особенно в методе Симпсона

Ответы

▲ 1Принят

Начнем с того, что интеграл ваш равен 3,55381...

А продолжать уже и не надо.

▲ 0

Не ответ, но полезная информация. Графическое отображение скорости сходимости методов на основе вашего кода. Слева - логарифмическая шкала ошибки. Как видно, метод Симпсона сходится очень быстро. Ну очень. И упирается в точность вычислений. Может быть об этом и говорил преподаватель? А метод прямоугольников - наоборот, сходится медленно. А метод Ньютона-Котеса вообще не видно на картинке, потому что его график в точности совпадает с методом трапеций и перекрывается этим графиком. Либо это математически и правда один и тот же метод, просто записанный по-разному, либо у вас какая-то ошибка в реализации.

введите сюда описание изображения

▲ -1

Numpy там есть вроде float128, Numeric Python(https://docs.python.org/3/library/numeric.html), Scipy