Определённый интеграл методом трапеций и прямоугольников с заданной точностью

Всем доброго времени суток! Столкнулся со следующей проблемой при подсчете определенного интеграла функции f(x) = sin(x)*cos(x^2) на отрезке [a, b] и с заданной точностью.

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

Точность Метод трапеций Метод прямоугольников
0.01 0.100304 0.0791528
0.001 0.100341 0.100349
0.0001 0.100345 0.0982234

Правильный ответ в моем случае (по вольфраму) должен быть 0.100345.

Для реализации методов я сначала находил количество отрезков разбиения n с помощью формул абсолютных погрешностей этих двух методов:

Погрешность метода трапеций

и

погрешность метода прямоугольнков

Ниже представлен код для поиска количества отрезков разбиения для методов трапеций (для метода прямоугольников код почти идентичный, за исключением коэффициента в знаменателе дроби при поиске погрешности)

int n = 1;
double max = fabs(sec_derivative(eps, a));
for (double i = a + eps; i <= b; i += eps) {
    if (max < fabs(sec_derivative(eps, i))) {
        max = fabs(sec_derivative(eps, i));
    }
}
double fault = max * pow((b - a), 3) /(12* pow(n, 2));
while (fault > eps) {
    n++;
    fault = max * pow((b - a), 3) / (12 * pow(n, 2));
}
double h = (b - a) / n;

Вторую производную брал следующим образом:

double sec_derivative(double eps, double x) {
    return (f(x + eps) - 2 * f(x) + f(x - eps)) / pow(eps, 2);
}

Далее находил, собственно, сам ответ:

double ans = 0; //метод прямоугольников
for (double i = a; i < b; i += h) {
    ans += f(i + (h / 2));
}
ans *= h;
return ans;

и

double ans = 0; //метод трапеций
for (double i = a + h; i < b - h; i += h) {
    ans += f(i);
}
ans *= 2;
ans += f(a) + f(b);
ans *= h / 2;
return ans;

Никак не могу понять, в чем моя ошибка(и есть ли она вообще?), поэтому подскажите, пожалуйста!

По ходу решения задачи возник вопрос из раздела математики: формулу для приближенного значения второй производной взял из интернета, но при собственном выводе получилось очень похоже, но в аргументе каждой функции получилось значение, большее на некое Eps, т.е. f(x + 2*eps) вместо f(x + eps) и т.д.

Понимаю, что разница выйдет не особо критичной, но в случае формулы, взятой из интернета ответ получается более точный, нежели с моей. Не понимаю, по какому принципу вывели эту формулу (просто вычли из каждого аргумента Eps и получили более правильный ответ?) и вообще, как вывести формулы для приближенных значечний производных бо́льших порядков (получилось вывести для производной 4-й степени, но в связи с вышеописанной проблемой не уверен, что получилось верно)


Ответы (1 шт):

Автор решения: Harry

И все же я бы решал путем удвоения количества отрезков...

double trapez(double(*f)(double), double a, double b, double eps)
{
    double old_i = 0, new_i = old_i+2*eps;
    for(unsigned int n = 1; abs(new_i-old_i) > eps; n *= 2)
    {
        old_i = new_i;
        double h = (b-a)/n, s = -(f(a) + f(b))/2;
        for(int i = 0; i <= n; ++i)
            s += f(a + i*h);
        new_i = s*h;
    }
    return new_i;
}

double y(double x) { return sin(x)*cos(x*x); }

int main(int argc, char * argv[])
{
    cout << trapez(y,0,5,1e-6) << endl;
}

Ответ — как у Wolfram'а :)

→ Ссылка