Насколько я знаю, в стандартной библиотеке нет функций того типа, который вы ищете. Вот одна из реализаций:
Расширенное правило трапеций.
Чтобы фиксированная функция f(x)
интегрировалась между фиксированными пределами a
и b
, можно удвоить количество интервалов в расширенном правиле трапеций без потери преимуществ предыдущей работы. Самая грубая реализация правила трапеций состоит в усреднении функции в ее конечных точках a
и b
. Первый этап уточнения заключается в добавлении к этому среднему значению функции в средней точке. Второй этап уточнения заключается в добавлении значений в точках 1/4
и 3/4
.
Ряд элементарных квадратурных алгоритмов включает в себя добавление последовательных этапов уточнения. Эту функцию удобно инкапсулировать в структуру Quadrature
:
struct Quadrature
{
//Abstract base class for elementary quadrature algorithms.
Int n; // Current level of refinement.
virtual Doub next() = 0;
//Returns the value of the integral at the nth stage of refinement.
//The function next() must be defined in the derived class.
};
Затем структура Trapzd
получается из этого следующим образом:
template<class T>
struct Trapzd: Quadrature
{
Doub a, b, s; // Limits of integration and current value of integral.
T &func;
Trapzd() { };
// func is function or functor to be integrated between limits: a and b
Trapzd(T &funcc, const Doub aa, const Doub bb)
: func(funcc), a(aa), b(bb)
{
n = 0;
}
// Returns the nth stage of refinement of the extended trapezoidal rule.
// On the first call (n = 1), the routine returns the crudest estimate
// of integral of f x / dx in [a,b]. Subsequent calls set n=2,3,... and
// improve the accuracy by adding 2n - 2 additional interior points.
Doub next()
{
Doub x, tnm, sum, del;
Int it, j;
n++;
if (n == 1)
{
return (s = 0.5 * (b-a) * (func(a) + func(b)));
}
else
{
for (it = 1, j = 1; j < n - 1; j++)
{
it <<= 1;
}
tnm = it;
// This is the spacing of the points to be added.
del = (b - a) / tnm;
x = a + 0.5 * del;
for (sum = 0.0,j = 0; j < it; j++, x += del)
{
sum += func(x);
}
// This replaces s by its refined value.
s = 0.5 * (s + (b - a) * sum / tnm);
return s;
}
}
};
Применение:
Структуру Trapzd
можно использовать несколькими способами. Самый простой и грубый способ — это интегрировать функцию по расширенному правилу трапеций, когда вы заранее знаете, сколько шагов вам нужно. Если вы хотите 2^M + 1
, вы можете сделать это с помощью фрагмента:
Ftor func; // Functor func here has no parameters.
Trapzd<Ftor> s(func, a, b);
for(j = 1 ;j <= m + 1; j++) val = s.next();
с ответом, возвращенным как val
. Здесь Ftor
— функтор, содержащий интегрируемую функцию.
Бонус:
Гораздо лучше, конечно, уточнять правило трапеций до тех пор, пока не будет достигнута некоторая заданная степень точности. Функция для этого:
template<class T>
Doub qtrap(T &func, const Doub a, const Doub b, const Doub eps = 1.0e-10)
{
// Returns the integral of the function or functor func from a to b.
// The constants EPS can be set to the desired fractional accuracy and
// JMAX so that 2 to the power JMAX-1 is the maximum allowed number of
// steps. Integration is performed by the trapezoidal rule.
const Int JMAX = 20;
Doub s, olds = 0.0; // Initial value of olds is arbitrary.
Trapzd<T> t(func, a, b);
for (Int j = 0; j < JMAX; j++)
{
s = t.next();
if (j > 5) // Avoid spurious early convergence.
{
if (abs(s - olds) < eps * abs(olds) || (s == 0.0 && olds == 0.0))
{
return s;
}
}
olds = s;
}
throw("Too many steps in routine qtrap");
}
Типы.
typedef double Doub; // 64 - bit floating point
typedef int Int; // 32 - bit signed integer
person
Ziezi
schedule
24.09.2015