Опубликован: 18.05.2011 | Доступ: свободный | Студентов: 871 / 65 | Оценка: 4.40 / 4.20 | Длительность: 12:30:00
Лекция 9:

Oбъектно-ориентированная реализация числовых функций

< Лекция 8 || Лекция 9: 123 || Лекция 10 >
Аннотация: Рассмотрено понятие конструктивной действительной функции. Рассмотрена реализация класса "функция".

Цель лекции: Научить создавать классы, для описания функций и реализации операций над функциями.

Пусть X и Y - произвольные множества. Мы под абстрактной функцией F будем понимать правило, которое элементу множества X сопоставляет элемент множества Y. Записывается это в виде

F:X\to Y.
Мы будем рассматривать только однозначные функции. В противном случае всегда можно вместо множества Y рассматривать подмножества множества Y. Функция F может быть определена не на всем множестве X, а только на некотором (непустом) подмножестве D\subset X. Множество D называется областью определения функции F.

Мы будем рассматривать функции F, определенные на подмножествах \Bbb{R}. Однако в качестве множества Y у нас могут выступать различные множества. Для этого создадим универсальный класс, который сможет представлять любые другие объекты.

\begin{verbatim}
class TElement
{
    object A; // место для любого объекта
    public TElement(object A)
    {
        SetA(A);
    }
    public object GetA()
    {
        return A;
    }
    public void SetA(object A)
    {
        this.A = A;
    }
}
\end{verbatim}

Заметим, что мы воспользовались типом object. Этот тип является родительским для всех объектов C#, поэтому возможно в классе TElement хранить ссылку на любой объект (элемент множества Y ).

Абстрактный класс представляющий функцию, заданную на некотором отрезке [a,b], выглядит следующим образом

\begin{verbatim}
    abstract class TAFunc
    {
        protected double a, b;

        public TAFunc(double a, double b)
        {
            this.a = a;
            this.b = b;
        }

        public double Get_a()
        {
            return a;
        }

        public double Get_b()
        {
            return b;
        }

        public TElement Calc(double x)
        {
            if ((x < a) || (x > b))
            {
                return null;
            }
            else
            {
                return CalcVal(x);
            }
        }

        protected abstract TElement CalcVal(double x);
    }
\end{verbatim}
Для реализации заданной функции, необходимо создать класс наследник, в котором нужно переопределить метод CalcVal. Для случая числовых функций, в которых множество Y также является \Bbb{R}, мы определим более удобный класс, наследник от TAFunc.
\begin{verbatim}
    abstract class TRFunc : TAFunc
    {
        public TRFunc(double a, double b) : base(a, b) { }

        public double CalcY(double x)
        {
            return (double)Calc(x).GetA();
        }
    }
\end{verbatim}
В этом классе метод CalcY возвращает тип double, а не object, поэтому нет необходимости в преобразовании типов.

Покажем как выглядит класс для описания функции sin.

\begin{verbatim}
    class TSinFunc : TRFunc
    {
        public TSinFunc(double a, double b) : base(a, b) { }
        protected override TElement CalcVal(double x)
        {
            TElement res = new TElement(Math.Sin(x));
            return res;
        }

    }
\end{verbatim}

Теперь покажем, как с помощью объектно-ориентированного подхода можно выполнять различные операции над функциями. Создадим класс, который будет представлять собой производную от исходного класса-функции.

\begin{verbatim}
    class TDiffFunc : TRFunc
    {
        protected TRFunc Func;
        double h;

        public TDiffFunc(TRFunc Func, double h)
        : base(Func.Get_a(), Func.Get_b())
        {
            this.Func = Func;
            this.h = h;
        }

        protected override TElement CalcVal(double x)
        {
            TElement res = new TElement(0);
            double D;

            if ((x + h) <= b)
            {
                D = (Func.CalcY(x + h) - Func.CalcY(x)) / h;
            }
            else
            {
                D = (Func.CalcY(x) - Func.CalcY(x - h)) / h;
            }

            res.SetA(D);
            return res;
        }
    }
\end{verbatim}

Теперь с использованием наших классов мы вычислим производные от функции y=\sin(x).

\begin{verbatim}
    TSinFunc Sin = new TSinFunc(0, 2.0 * Math.PI);

    TDiffFunc DSin = new TDiffFunc(Sin, 0.00001);
    TDiffFunc D2Sin = new TDiffFunc(DSin, 0.0001);

    double x0 = Math.PI / 2.0;

    Console.WriteLine("DSin({0}) = {1}", x0, DSin.CalcY(x0));
    Console.WriteLine("D2Sin({0}) = {1}", x0, D2Sin.CalcY(x0));
\end{verbatim}
При выполнении этого кода мы получим:
\begin{verbatim}
DSin(1.5707963267949) = -5.00000041370186E-06
D2Sin(1.5707963267949) = -0.999999971718068
\end{verbatim}
Что близко к точным значениями 0 и -1.

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

Мы дадим определение функции Маркова. Но сначала мы должны ответить на естественный вопрос - а какие конструктивные действительные числа называются равными? Если исходить из того, что конструктивно действительное число - это пара алгоритмов, то из неравенства этих алгоритмов еще не следует неравенство конструктивных действительных чисел. Поэтому мы будем говорить, что x равно y и писать x=y, если существует такая вычислимая функция r:\Bbb{Q}\to\Bbb{N}, что

|x(n)-y(n)|<\varepsilon,
для всех n>r(\varepsilon).

Пусть {\cal A} - некоторое множество конструктивных действительных чисел такое, что если x\in{\cal A} и y - другое конструктивное действительное число и x=y, то y\in{\cal A}. Конструктивной функцией или функцией Маркова называется такой алгоритм f(x), что

  1. Для любого x \in A определено f(x) и f(x) есть конструктивное действительное число.
  2. Если x и y суть конструктивные действительные числа, x\in{\cal A} и x=y, то f(x)=f(y).

Ключевые термины

Абстрактная функция - однозначное отображение одно множества в другое.

Конструктивная функция - алгоритм сопоставляющий одному конструктивному действительному числу другое конструктивное действительное число.

Область определения функции - множество на, котором определена функция.

Краткие итоги: Реализован абстрактный класс на языке C#, реализующий функции. Разработаны классы, реализующие конкретные числовые функции и операции над ними.

< Лекция 8 || Лекция 9: 123 || Лекция 10 >
Дмитрий Кифель
Дмитрий Кифель
Казахстан, Темиртау