Отправляет email-рассылки с помощью сервиса Sendsay

Всё о работе в Интернет

  Все выпуски  

Занятие 46. Вычисление суммы заданнго числа членов последовательности рекуррентного типа. Один из простейших способов повышения надёжности работы программы.


Сегодня, уважаемые подписчики, мы с вами продолжим изучение методов программирования основных типов циклических алгоритмов.

Кроме упомянутого, мы рассмотрим также один из простейших методов повышения надёжности программ. И в этом тоже нам поможет циклический алгоритм.  

СУММА ЧЛЕНОВ ПОСЛЕДОВАТЕЛЬНОСТИ РЕКУРРЕНТНОГО ТИПА

1. Обсуждение алгоритма вычисления суммы членов последовательности.

Решим следующую задачу.

Задача C.1.4. “Сумма членов последовательности рекуррентного типа”. Бесконечная числовая последовательность рекуррентного типа задана с помощью формулы общего члена i = f ( A i  1 , i ), A1=const, i = 23, ... . Построить подпрограмму вычисления суммы первых N членов этой последовательности (³ 0).

Как видим, в данной задаче использован тот же способ задания рекуррентной последовательности, что и в предыдущей, а именно: рекуррентная последовательность в целом представлена комбинированной формулой, в которой первый член определён как константа.

Из собственного опыта мне известно, что большинству обучаемых в первую очередь приходит в голову следующая идея решения поставленной задачи: вычислять члены последовательности, обращаясь к алгоритму C.1.3 “Член последовательности рекуррентного типа”, а суммировать их с помощью алгоритма, аналогичного алгоритму C.1.1 “Сумма членов последовательности простого типа”. При таком подходе получается нечто следующее:

Function Sum_Recurrent_Sequence(A:Real;N:Integer;f:TFunction):Real;
   Var i: Integer; S: Real;
Begin
   S := 0;
   For i:=1 To N Do S := S + Part_Sequence(A,i,f);
   Sum_Recurrent_Sequence := S
End;

Отметим сразу,что в таком виде алгоритм является никуда не годным, поскольку при обращении к функции Part_Sequence(A,i,f) в цикле вычисление одних и тех же членов последовательности выполняется неднократно. Например, при i=5 к сумме S должен быть добавлен пятый член последовательности. Чтобы получить его, функция Part_Sequence(A,i,f) в соответствии со своим алгоритмом сначала последовательно вычисляет первые четыре. Затем, при добавлении к сумме шестого члена последовательности функция Part_Sequence(A,i,f) повторно вычисляет первые пять и т. д.

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

Таким образом, нужная нам подпрограмма приобретает следующий вид:

Function Sum_Recurrent_Sequence(A:Real;N:Integer;f:TFunction):Real;
   Var i: Integer; S: Real;
Begin
   S := 0;
   For i:=1 To N Do Begin S := S + A; A := f(A,i+1) End;
   Sum_Recurrent_Sequence := S
End;

Ещё раз отметим характерные особенности этой подпрограммы.

Значение первого члена последовательности A известно, так как он задан в качестве аргумента подпрораммы. Поэтому в цикле вычисления суммы в первую очередь выполняется сложение. И только после этого вычисляется очередной член последовательности. В связи с этим в обращении к функции вычисления члена последовательности f(A,i+1) указывается порядковый номер i+1. В самой же функции f реализовано вычисление только второй ветви комбинированной функции (см. алгоритм C.1.3). Здесь важно также то, что в операторе  A:=f(A,i+1) очередной член последовательности обозначен так же, как и предыдущий.

Функция вычисления очередного члена последовательности f(A,i), указанная в качестве формального параметра подпрограммы C.1.4, имеет нестандартный процедурный тип TFunction, который предварительно должен быть определён в разделе типов программы следующим образом:   Type TFunction = Function(A: Real; i: Integer): Real. Для функций, имена которых предполагается использовать в качестве фактических параметров обращения к подпрограмме C.1.4, или для программы в целом должна устанавливаться дальняя модель памяти.

Чтобы найти сумму первых N членов рекуррентной последовательности, приведённой в качестве примера (см. материалы занятия 45), к подпрограмме Sum_Recurrent_Sequence следует обратиться, например, так: S:=Sum_Recurrent_Sequence(2.5,N,f).  

Отметим, что для данной подпрограммы остаются в силе уже известные положения в отношении отбрасывания индексов, использования рекуррентных соотношений и установки нулевых начальных значений процесса суммирования; о допустимости значений аргумента N³0 и о неоднозначности получаемых в некоторых случаях значений результатов, например, при N=0; о возможности построения по аналогичной схеме алгоритма вычисления произведения первых N членов этой же последовательности.

2. Повышение надёжности выполнения программы.

Приведём полный текст программы C.1.3 (см. материалы занятия 45).

{$B+,D+,E+,F+,I+,L+,N+,Q+,R+,X-}
Program C_01_03;
   Type
      TFunction = Function ( A: Real; i: Integer): Real;
   Function f ( A: Real; i: Integer ): Real;
   Begin
      f := A * Ln(1.5 + Cos(i))
   End;
   Function Part_Sequence(A: Real; N: Integer; f: TFunction ): Real;
      Var i: Integer;
   Begin
      For i:=2 To N Do A := f(A,i);
      Part_Sequence := A
   End;
   Var N: Integer;
Begin
  Repeat
    Write('
Введите порядковый номер члена последовательности: N= ');
    ReadLn(N)
  Until N>=1;
  WriteLn('
Член последовательности: A=',Part_Sequence(2.5,N,f):0:4);
  ReadLn
End.

Полный текст программы C.1.3 приведён с целью прокомментировать специфическую организацию ввода исходных данных с клавиатуры. Использование оператора цикла-ДО обусловлено необходимостью обеспечить повторный ввод исходных данных, если перед этим были введены недопустимые их значения. Поэтому в качестве условия завершения оператора цикла указываются допустимые значения исходных данных.

Рассмотренная организация ввода исходных данных относится к средствам защиты программы от неправильных действий пользователя. И, разумеется, этого явно недостаточно. Например, программа не сможет помешать ввести с клавиатуры нечисловые или дробные значения, а также значения, выходящие за пределы типа Integer. Однако такие ошибки ввода будут выявлены операционной системой, что приведёт к немедленному завершению работы программы с соответствующим диагностическим сообщением. Таким образом, построение и использование даже простейших способов защиты программ полезно, так как может явиться дополнением защитных функций операционной системы.

Уважаемые подписчики! При необходимости задать вопрос, проконсультироваться, уточнить или обсудить что-либо обращайтесь через Гостевую книгу моего персонального сайта http://a-morgun.narod.ru. При этом настоятельно рекомендую пользоваться браузером Internet Explorer.

С уважением, Александр.


В избранное