Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лр1_Делегаты.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
187 Кб
Скачать
☆

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, вызывающий метод вычисления интеграла.

Результат вычисления интеграла с использованием функций высших порядков