- •Тверской государственный технический университет
- •Делегаты.
- •Содержание
- •2.5. Функции высших порядков.
- •1. Содержание отчета по лабораторной работе.
- •2. Теоретическая часть
- •2.1. Функциональный тип и его экземпляры
- •2.2. Одиночные делегаты
- •2.4. Комбинированные делегаты
- •2.3. Класс Delegate
- •2.5. Функции высших порядков
- •2.6. Вычисление интеграла
- •3. Задание на лабораторную работу.
- •4. Вопросы для самопроверки:
- •Приложение. Вычисление площади методом трапеций
2.5. Функции высших порядков
Одно из наиболее важных применений делегатов связано с функциями высших порядков. Функцией высшего порядка называется такая функция (метод) класса, у которой один или несколько аргументов принадлежат к функциональному типу. Без этих функций в программировании обойтись довольно трудно. Классическим примером является функция вычисления интеграла, у которой один из аргументов задает подынтегральную функцию. Другим примером может служить функция, сортирующая объекты. Аргументом ее является функция Compare, сравнивающая два объекта. В зависимости от того, какая функция сравнения будет передана на вход функции сортировки, объекты будут сортироваться по-разному, например, по имени, или по ключу, или по нескольким полям. Вариантов может быть много, и они определяются классом, описывающим сортируемые объекты.
2.6. Вычисление интеграла
Давайте более подробно рассмотрим ситуацию с функциями высшего порядка на примере задачи вычисления определенного интеграла с заданной точностью. С этой целью создадим класс, в котором будет описан делегат, определяющий контракт, коему должны удовлетворять подынтегральные функции. В этом же классе определим метод, вычисляющий интеграл. По сути самой задачи этот метод представляет собой функцию высшего порядка. Приведу программный код, описывающий класс:
public class HighOrderIntegral
{
// Делегат
public delegate double SubIntegralFun(double x);
public double EvalIntegral(double a, double b, double eps, SubIntegralFun fun)
{
int n=4;
double I0=0, I1 = I( a, b, n, fun);
for( n=8; n < Math.Pow(2.0,15.0); n*=2)
{
I0 =I1; I1=I( a, b, n, fun );
if(Math.Abs(I1-I0)<eps) break;
}
if(Math.Abs(I1-I0)< eps)
Console.WriteLine("Требуемая точность достигнута! "+
" eps = {0}, достигнутая точность ={1}, n= {2}",
eps,Math.Abs(I1-I0),n);
else
Console.WriteLine("Требуемая точность не достигнута! "+
" eps = {0}, достигнутая точность ={1}, n= {2}",
eps,Math.Abs(I1-I0),n);
return(I1);
}
private double I(double a, double b, int n, SubIntegralFun fun)
{
//Вычисляет частную сумму по методу трапеций
double x = a, sum = fun(x)/2, dx = (b-a)/n;
for (int i= 2; i <= n; i++){ x += dx; sum += fun(x); }
x = b; sum += fun(x)/2;
return(sum*dx);
}
}
Прокомментируем этот текст:
Класс HighOrderIntegral предназначен для работы с функциями. В него вложено описание функционального класса - делегата SubIntegralFun, задающего класс функций с одним аргументом типа double и возвращающих значение этого же типа.
Метод EvalIntegral - основной метод класса позволяет вычислять определенный интеграл. Этот метод есть функция высшего порядка, поскольку одним из его аргументов является подынтегральная функция, принадлежащая классу SubIntegralFun.
Для вычисления интеграла применяется классическая схема. Интервал интегрирования разбивается на n частей, и вычисляется частичная сумма по методу трапеций, представляющая приближенное значение интеграла. Затем n удваивается, и вычисляется новая сумма. Если разность двух приближений по модулю меньше заданной точности eps, то вычисление интеграла заканчивается, иначе процесс повторяется в цикле. Цикл завершается либо по достижении заданной точности, либо когда n достигнет некоторого предельного значения (в нашем случае - 215).
Вычисление частичной суммы интеграла по методу трапеций реализовано закрытой процедурой I.
Впоследствии класс может быть расширен, и помимо вычисления интеграла он может вычислять и другие характеристики функций.
Чтобы продемонстрировать работу с классом HighOrderIntegral, введем еще один класс Functions, где описано несколько функций, удовлетворяющих контракту, который задан классом SubIntegralFun:
class Functions
{
//подынтегральные функции
static public double fun1(double x)
{
int k = 1; int b = 2;
return (double)(k*x +b);
}
static public double fun2(double x)
{
double a = 1.0; double b = 2.0; double c= 3.0;
return (double)(a*x*x +b*x +c);
}
}
А теперь рассмотрим метод класса клиента, выполняющий создание нужных объектов и тестирующий их работу:
public void TestApp()
{
double val=0.0;
HighOrderIntegral f = new HighOrderIntegral();
HighOrderIntegral.SubIntegralFun f1 =
new HighOrderIntegral.SubIntegralFun(Functions.fun1);
val = f.EvalIntegral( 2, 3, 0.1e-5, f1);
Console.WriteLine("myintegral1 = {0}",val);
HighOrderIntegral.SubIntegralFun f2 =
new HighOrderIntegral.SubIntegralFun(Functions.fun2);
val= f.EvalIntegral( 2, 3, 0.1e-5, f2);
Console.WriteLine("myintegral2 = {0}",myint1);
}
Здесь создаются два экземпляра делегата и объект класса HighOrderIntegral, вызывающий метод вычисления интеграла.
Результат вычисления интеграла с использованием функций высших порядков
