КаталогИндекс раздела
НазадОглавлениеВперед


Лабораторная работа ╧6

Операторы цикла в языке C

1. Цель работы

     Целью лабораторной работы является получение практических навыков в работе с операторами цикла языка C.

2. Темы для предварительной проработки

3. Задания для выполнения

     Для ряда, члены которого вычисляются по формуле, соответствующей Вашему индивидуальному заданию, подсчитать сумму членов ряда с точностью до 0.000001 и сумму первых 10 членов ряда. Если Вы считаете это необходимым, можете упростить или преобразовать выражение.

4. Варианты индивидуальных заданий

 1        2        3        4        5        6        7        8        9       10      
11       12       13       14       15       16       17       18       19       20      
21       22       23       24       25       26       27       28       29       30      

5. Пример решения задачи (вариант 30)

5.1. Разработка алгоритма решения.

     5.1.1. Общий метод решения
     Очевидно, что процесс подсчета суммы членов ряда должен быть итерационным: следует повторять вычисления по одной и той же формуле при значениях n=0, 1, 2, ... . В каждой итерации цикла следует выполнять вычисления по заданной формуле для текущего значения n, т.е. подсчитывать очередной член ряда. Полученное значение следует прибавлять к переменной, которая представляет сумму. Эта переменная в каждой итерации будет содержать в себе сумму всех уже обработанных членов ряда, следовательно, ее начальное значение (когда ни один член еще не обработан) должно быть 0. После вычисления суммы при значении n=9 следует вывести значение суммы - это один из результатов программы в соответствии с заданием (берется значение 9, т.к. первый член ряда вычисляется при n=0, таким образом, девятый - при n=9). После вычисления каждого члена ряда (но до прибавления его значения к сумме) следует сравнить полученное значение с заданным пределом точности. Из-за того, что значение члена ряда может быть как положительным, так и отрицательным, при сравнении следует использовать абсолютное значение. Если абсолютное значения члена ряда не превышает предела точности, следует закончить вычисления: выйти из цикла напечатать значение суммы и завершить программу.

     5.1.2. Алгоритм вычисления 2n
     Для выполнения возведения в степень можно применить библиотечную функцию C pow(x,y) . Но есть возможность получения этого значения более эффективным способом. В каждой следующей итерации цикла значение этого выражения вдвое больше, чем в предыдущей. Так что, будет целесообразно выделить отдельную переменную для сохранения значения 2n. Ее начальное значение должно быть 20 = 1, а в конце каждой итерации оно должно удваиваться.

     5.1.3. Алгоритм вычисления (-1)n
     В этом случае также нецелесообразно применять функцию возведения в степень. Значение этого выражения будет 1 при четных значениях n и -1 - при нечетных. Так что, можно выделить переменную для сохранения значения этого выражения. Ее начальное значение должно быть (-1)0=1, а в конце каждой итерации оно должно менять знак на противоположный.

     5.1.4. Схема алгоритма
     Мы построили начальный (не показанный здесь) вариант схемы алгоритма на базе соображений, высказанных в пп.5.1.1, а потом усовершенствовали его. Результирующий вариант схемы алгоритма показан на рисунке.

5.2. Определение переменных программы

     Все переменные нашей программы соответствуют переменным, которые введены в схеме алгоритма. Дополнительно определим их типы.

n - параметр ряда; по условиям задачи это - целое число; поскольку заранее неизвестно, сколько итераций цикла будет нужно для достижения предела точности, объявим его как "длинное целое":

    long n;

     Отметим, что хотя по условию задания n - целое, результаты выражений, в которых фигурирует n, будут иметь дробную часть. Преобразование типов можно выполнять непосредственно при вычислении выражения, но чтобы заранее исключить ошибки, введем еще одну переменную - dbln, которая будет представлять значение n как числа с плавающей точкой:
    double dbln;

term - значение текущего члена ряда. Объявим его как:

    double term;

sum - текущее значение суммы ряда с начальным значением 0. Объявим его как:

    double sum=0;

k2 - переменная для сохранения текущего значения 2n с начальным значением 1 (см. пп.5.1.2). Она должна быть "длинным целым" - из тех же соображений, что и n:

    long k2=1;

k1 - переменная для сохранения текущего значения (-1)n с начальным значением 1 (см. пп.5.1.3). Для нее достаточно быть "коротким целым":

    short k1=1;

eps - переменная для представления заданного предела точности. Она должна иметь начальное (неизменное) значение 0.000001, поэтому может быть объявлена как const. Использование переменной для представления константы вместо употребления константы непосредственно в операторах программы может повысить гибкость программы:

    const double eps=0.000001;

5.3. Разработка текста программы

     Начинаем разработку текста программы с заголовка главной функции main():

    int main(void)

     Далее открывается тело функции, и в него включаются определения переменных (см. п.5.2). Определения переменных реализуют блок 2 схемы алгоритма. В дополнение к переменным, определенным в схеме алгоритма, объявляем рабочую переменную dbln и константу eps. Поскольку правила языка C позволяют присваивать переменным начальные значения, в объявлении переменных отчасти реализован также и блок 3. Блоки 4 - 9 схемы алгоритма образуют цикл. В языке С есть два "простых" оператора цикла: цикл с предусловием - while и цикл с постусловием - do-while. Но по схеме алгоритма видно, что выход из цикла происходит в середине тела цикла (блок 5): после вычисления члена ряда, но до добавления его значения к сумме. Следовательно, "простые" циклы применить нельзя. "Сложный" оператор цикла - for - является циклом с предусловием, но задавать условие в самом операторе цикла необязательно. К тому же этот оператор дает возможность определить действия, которые нужно выполнить до начала цикла и действия, которые выполняются в конце каждой итерации. Таким образом, открытие цикла будет иметь вид:

    for (n=0; ; n++, k2*=2, k1=-k1) {
где первый параметр for - присваивание начального значения переменной n (остаток блока 3), второй параметр - условие выхода из цикла - пустой, третий параметр реализует блок 8 схемы алгоритма. В теле цикла содержится несколько отдельных действий, значит, будет несколько операторов, поэтому тело цикла берется в операторные скобки.

     В теле цикла первый оператор:

    dbln=n;
это действие не предусмотрено в схеме алгоритма, но его необходимость мы пояснили в п.5.2.

     Далее вычисляется значение текущего члена ряда:

    term=k1*(dbln+1)/(dbln*dbln+k2);
этот оператор полностью реализует блок 4 и формулу из индивидуального задания (учитывая пп.5.1.2, 5.1.3) за исключением того, что вместо операции возведения в степень 2 мы применяем умножение.

     Следующее действие - проверка достижения предела точности - на схеме алгоритма представлена блоком 5 и выполняется условным оператором, который начинается с:

    if (fabs(term)>=eps) 

     Следует отметить, что сравнивается абсолютное значение term, а функция для получения абсолютного значения переменной типа double - fabs(). Эта функция описана в файле math.h, так что мы должны включить этот файл в начало программы:

    #include <math.h>

     Продолжение условного оператора, действие, которое выполняется при выполнении условия, - добавление значения члена к сумме (блок 6):

    sum+=term;

     При невыполнении условия мы должны выйти из цикла, так что условный оператор требует и второй части:

    else break;

     По схеме алгоритма нам надо проверить, не достигла ли переменная n значения 9 (блок 7), и, если да, - печатать значение суммы (блок 8). Это реализуется условным оператором:

    if (n==9)
  printf("Сумма 10 членов ряда = %10.7lf\n",sum);

     Поскольку при невыполнении условия не делается ничего, часть else для этого оператора не нужна.

     При вызове функции printf() всегда возникает проблема форматизации вывода. Мы включили в формат текст, который поясняет вывод, а значение переменной sum выводим по спецификации %10.7lf. Тип спецификации соответствует типу переменной - double, а числовые параметры мы выбрали произвольно, поскольку в задании не оговорены требования к точности вывода. Перед точкой мы оставляем 2 позиции - для знака и целой части (которая должна быть 0), после точки - 7 позиций, что на 1 превышает точность заданного предела точности. Функция printf() описана в файле stdio.h, поэтому мы включаем этот файл в начало программы:

    #include <stdio.h>

     Поскольку блок 9 схемы алгоритма реализован нами в заголовке цикла, то цикл на этом заканчивается, и мы ставим операторную скобку, закрывающую тело цикла.

     Выход из цикла происходит по оператору break в составе условного оператора. После выхода из цикла мы должны напечатать окончательное значение суммы (блок 10), что мы и делаем оператором:

    printf("Полная сумма ряда = %10.7lf\n",sum);

     При определении формата вывода работают те же соображения, что и в предыдущем случае.

     Реализация алгоритма закончена, мы ставим операторную скобку, которая закрывает тело функции main().

     Полный текст программы приведен ниже.

/****************************************************/
/*              Лабораторная работа ╧6              */
/*               Вычисление суммы ряда              */
/*          Пример выполнения. Вариант ╧30.         */
/****************************************************/
#include <stdio.h>
#include <math.h>
int main(void) {
 long n;              /* параметр ряда */
 double dbln;         /* параметр ряда в форме с плавающей точкой */
 double sum=0;        /* сумма членов ряда */
 double term;         /* значение текущего члена */
 const double eps=0.000001;  /* предел точности */
 long k2=1;           /* pow(2,n)*/
 short k1=1;          /* pow(-1,n)*/
   /* основной цикл; в модификациях вычисляются 
      следующие значения pow(2,n) и pow(-1,n)*/
   for (n=0; ; n++, k2*=2, k1=-k1) {
     /* преобразование n в форму с плавающей точкой */
     dbln=n;
     /* вычисление очередного члена */                     
     term=k1*(dbln+1)/(dbln*dbln+k2);
     /* проверка достижения предела точности */       
     if (fabs(term)>=eps) 
        /* если не достигнут - накопление суммы */ 
        sum+=term;
     /* если достигнут - выход из цикла */ 
     else break; 
     /* если 10 членов - вывод суммы */               
     if (n==9)       
        printf("Сумма 10 членов ряда = %10.7lf\n",sum);
     }
   /* конец основного цикла */
   /* вывод окончательной суммы */
   printf("Полная сумма ряда = %10.7lf\n",sum);    
  return 0;
} /* конец программы */

5.4. Отладка программы

     При отладке программы целесообразно использовать пошаговый режим с отслеживанием значений переменных - прежде всего: n, term, sum. Следует выполнить шаг за шагом несколько итераций цикла, убеждаясь, что эти переменные получают правильные значения. В таком режиме нетрудно выполнить 10 итераций и убедиться в правильном формировании первого результата. Если возникают ошибки при вычислении наиболее сложного выражения в программе: term=k1*(dbln+1)/(dbln*dbln+k2); можно включить в программу временные дополнительные переменные и разбить выражение на простые составляющие, проверяя на шаг за шагом значения этих переменных. Например:

   double temp1, temp2; /* временные переменные */
   . . .
   temp1=dbln+1;
   temp2=dbln*dbln;
   temp2=temp2+k2;
   temp1=temp1/temp2;
   term=k1*temp1;

     Для того, чтобы убедиться в правильном выводе второго результата, имеет смысл при отладке выводить вместе с суммой и номер итерации, на котором закончилась робота цикла, и значение члена ряда, которое оказалось меньше предела точности:

    printf("%ld %10.7lf\n",n,term); 

5.5. Результаты работы программы

     При работе программы на экран были выведены такие результаты:

Сумма 10 членов ряда = 0.5600899
Полная сумма ряда = 0.5663245

5.6. Выводы

     При выполнении лабораторной работы изучены вопросы:


КаталогИндекс раздела
НазадОглавлениеВперед