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

Научное программирование

< Лекция 6 || Лекция 7: 123 || Лекция 8 >

Практическое занятие "Вычислительные процедуры"

Цель занятия

Продемонстрировать на практике различные вычислительные процедуры. Научится самостоятельно реализовывать вычислительные процедуры для решения задач численного анализа.

Практическая задача

Рассмотрим простую задачу вычисления факториала числа.

n!=1\cdot2\cdot3\cdot\ldots\cdot(n-1)\cdot n.
Чтобы вычислить факториал мы должны спроектировать и реализовать вычислительную процедуру. Покажем этим примером, как можно реализовать вычислительные процедуры, основанные на разных принципах. Для задачи вычисления факториала мы будем использовать процедуры, основанные на итерациях, и процедуры, основанные на рекурсии.

Первая вычислительная процедура выглядит следующим образом:

\begin{verbatim}
    public int F1(int N)
    {
        int res = 1;

        for (int i = 1; i <= N; i++)
        {
            res = res * i;
        }

        return res;
    }
\end{verbatim}

Вторая процедура будет основана на рекурсивном вызове:

\begin{verbatim}
    public int F2(int N)
    {
        if (N == 1)
        {
            return 1;
        }
        else
        {
            return N * F2(N - 1);
        }
    }
\end{verbatim}

С математической точки зрения - обе эти процедуры эквивалентны, но с вычислительной точки зрения между этими реализациями есть существенные различия. Чтобы оценить быстродействие наших процедур выполним следующий тест:

\begin{verbatim}
    int i;

    int A = 0;
    for (i = 0; i < N; i++)
    {
        A += F1(100);
    }

    Console.WriteLine("F1: {0}", A);

    A = 0;
    for (i = 0; i < N; i++)
    {
        A += F2(100);
    }

    Console.WriteLine("F2: {0}", A);
\end{verbatim}

Заметим, что кроме быстродействия необходимо рассматривать также и такой параметр, как требуемая память. Для рекурсивных процедур с большим уровнем вложения может потребоваться большой объем стека.

В лекции, посвященной вычислительным процедурам, мы отмечали, что из-за наличия машинного \varepsilon эквивалентные (с математической точки зрения) вычислительные процедуры могут давать различные результаты. В качестве примера - попробуем проверитЬ на компьютере выполнение различных тождеств:

\sin^2x+\cos^2x=1,
\ln e=1,
\cos 2\pi=1.
Для этого выполним следующий тест

\begin{verbatim}
double x = 3.0;

if ((Math.Cos(x) * Math.Cos(x) +
Math.Sin(x) * Math.Sin(x)) == 1.0)
{
    Console.WriteLine("Yes!");
}
else
{
    Console.WriteLine("No");
}

x = Math.E;

if (Math.Log(x) == 1.0)
{
    Console.WriteLine("Yes!");
}
else
{
    Console.WriteLine("No");
}

x = 2.0 * Math.PI;

if (Math.Cos(x) == 1.0)
{
    Console.WriteLine("Yes!");
}
else
{
    Console.WriteLine("No");
}
\end{verbatim}

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

y'(x)=ay(x), ( 1)
y(0)=C ( 2)
при x=T.

Известно, что решением задачи 1 - 2 будет число Ce^{aT}. Если мы будем решать эту задачу с помощью численного метода, например, метода Эйлера, то устойчивость нашей вычислительной процедуры будет зависеть от знака числа a. Если a>0, то наша вычислительная процедура является неустойчивой.

< Лекция 6 || Лекция 7: 123 || Лекция 8 >