Лабораторная работа №3.. Операторы цикла.




Лабораторная работа №3.

Операторы цикла.

Цели работы:

- проверка с помощью ЭВМ понимания порядка выполнения операторов цикла языка С++;

- знакомство с сообщениями транслятора языка С++ об обнаруженных ошибках в записи операторов цикла;

- получение практических навыков по отладке операторов цикла.

 

Основные сведения

Операторы повторения (цикла) используются в программах для организации повторяющихся действий с изменяемыми значениями данных. В языке С++ имеются три оператора цикла: оператор цикла с предусловием, оператор цикла с постусловием и оператор цикла с параметром.

Оператор цикла с предусловием записывается в следующем виде:

while <Условие> {

<Оператор>; // пока <Истина> делай

}

 

В этом операторе <Условие> (булево выражение) вычисляется и проверяется в начале цикла. Это выражение управляет повторением: если условие верно (TRUE), то оператор выполняется, в противном случае он пропускается и управление передается следующему за оператором цикла оператору. При использовании оператора цикла с предусловием необходимо обращать внимание на правильное формирование условия: перед выполнением цикла все переменные, входящие в условие, должны получить определенные значения, а при некотором повторении цикла значение одной переменной (или нескольких) должно измениться так, чтобы условие стало неверным (FALSE) во избежание зацикливания. <Оператор> цикла часто является составным, в этом случае его необходимо заключить в операторные скобки.

Пример: вывести на экране дисплея цифры 0, 1, 2,..., 9.

#include <iostream>

int main()

{

int Digit = 0; // начальное значение

while (Digit <= 9)

{

cout << setw(3) << Digit; // 3 - число знакомест на экране

Digit++; // для вывода значения

};

return 0;

}

 

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

do // повторять

<Oператор>;

while <Условие>; // пока Истина

При выполнении оператора цикла с постусловием условие вычисляется и проверяется в конце цикла. Повторение цикла продолжается, пока условие верно, т.е. его значение pавно TRUE. Когда <условие> станет неверным, управление передается оператору, следующему за оператором цикла. При составлении оператора цикла с постусловием необходимо следить за тем, чтобы все переменные, входящие в <условие>, получили перед и при выполнении оператора цикла такие значения, при которых начальное условие является правильно сформированным. Среди операторов внутри цикла должен присутствовать хотя бы один оператор, влияющий на условие окончания (иначе цикл будет продолжаться бесконечно); условие окончания в конце концов должно быть удовлетворено. <Оператор> цикла часто является составным, в этом случае его необходимо заключить в операторные скобки.

Используем оператор цикла с постусловием для решения предыдущего примера:

#include <iostream>

int main()

{

int Digit = 0;

do

{

cout << Digit;

Digit++;

}

while (Digit < 10); // при Digit == 10 - выход из цикла

return 0;

}

Операторы цикла с предусловием и постусловием используются, когда число повторений цикла заранее неизвестно.

 

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

for (Par = <ValueBegin>; Par <= <ValueEnd>; Par=Par+шаг)

// для каждого значения параметра Par от Начального

// до Конечного выполнить Оператор

<Оператор>;

или

for (Par = <ValueBegin>; Par >= <ValueEnd>; Par=Par-шаг)

// для каждого значения параметра Par от Начального

// до Конечного выполнить Оператор

<Оператор>;

где

ValueBegin, ValueEnd – выражения целого (или приводимого к целому типу, например, символьного, логического) типа, вычисляются один раз при входе в цикл;

Par – управляющая переменная (параметр цикла), имеет начальное значение ValueBegin, после выполнения оператора получает следующее значение: Par:= Par±шаг.

Выход из цикла с параметром происходит при Par > ValueEnd (или при Par < ValueEnd), эта проверка происходит каждый раз перед очередным выполнением оператора внутри цикла.

Пример использования оператора цикла с параметром:

 

#include <iostream>

using namespace std;

int main()

{

int Digit = 0;

for (Digit = 0; Digit <= 9; Digit++)

cout << setw(3) << Digit; // 0 1 2 3 4 5 6 7 8 9

cout << endl;

for (Digit = 9; Digit >= 0; Digit--)

cout << setw(3) << Digit; // 9 8 7 6 5 4 3 2 1 0

cout << endl;

return 0;

}

 

Параметр цикла может изменяться внутри цикла, что не рекомендуется. Это нарушит все разумные предположения читателя программы о содержании цикла. При этом компилятор не сообщает об изменении параметра цикла оператором внутри самого цикла. Например:

 

#include <iostream>

int main ()

{

for (int i = 0; i<100; ++i) { // Для i из диапазона [0, 100)

cout << i << '\t' << i*i << '\n';

++i; // Что это? Похоже на ошибку!

}

return 0;

}

 

Любой читатель, увидевший этот цикл, разумно предположит, что его тело будет выполнено 100 раз. Однако это не так. Инструкция ++i в его теле обеспечивает двойной инкремент счетчика i на каждой итерации, так что вывод будет осуществлен только для 50 четных чисел.

 

Для проверки понимания работы операторов цикла предлагается самостоятельно проанализировать следующую программу на языке C++, выполнив её по операторам при заданных значениях входных данных (табл. 1):

 

#include <iostream>

using namespace std;

int main ()

{

int w, r, s, i;

int P,Q,Z;

int Probel = 32; // ASCII-код пробела

 

cout << "Введите целые числа P, Q, Z от 1 до 10:\n";

cin >> P >> Q >> Z;

s = i = 0;

 

do {

s += (s*i+1);

++i;

} while (i!= P);

cout << (char)Probel << (char)(Probel + 51) << "=" << setw(4) << left << s;

 

r = i = 0;

while (i <= Q) {

r += i*i;

i++;

}

cout << (char) Probel << (char) 0x52 << "=" << setw(4) << left << r;

 

w = 2;

for (i=1; i<=Z; i++)

w = w+i*(w-1);

cout << " W=" << setw(4) << left << w << endl;

 

return 0;

}

 

Обратите внимание на способ вывода результатов. Вывод сообщений пользователю осуществляется не только с помощью строковых литералов (например, " W="), но и с помощью приведения ASCII-кодов нужных символов к соответствующим символам. Например, символ пробел выводится как (char)Probel, символ R – (char) 0x52, а при выводе символа S учитывается то, что он стоит в таблице ASCII-кодов на расстоянии 51 от пробела ((char)(Probel + 51)).

По результатам анализа программы должна быть заполнена таблица 1, в которой отражаются значения входных и выходных данных программы. Выходные данные, полученные при прокрутке вручную и проставленные в таблице, необходимо сравнить со значениями, полученными при выполнении лабораторной работы.

 

Таблица 1

Входные данные Выходные данные
P Q Z S R W
      Анализ Фактически Анализ Фактически Анализ Фактически
                 

 

Ошибки, допускаемые при использовании оператора цикла, можно, как обычно, разделить на две группы: синтаксические и семантические. Синтаксические ошибки распознаются на этапе трансляции и связаны с нарушением правил записи операторов цикла языка С++. Такими нарушениями могут быть: неверная запись ключевых слов for, do, while; неправильно сформированное логическое выражение при описании условий; неправильное использование типа в выражениях ValueBegin, ValueEnd и параметре цикла или их изменение операторами внутри цикла. Сообщения об ошибке транслятор выдает на экран дисплея вместе c перемещением текстового курсора в то место, где он ее обнаружил. Неправильная запись ключевых слов может привести к сообщениям, указывающим на отсутствие описаний идентификаторов, за которые принимаются неправильно записанные ключевые слова.

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

Семантические ошибки в операторах цикла – это ошибки, приводящие к преждевременному выходу из цикла, неверному числу повторений цикла или зацикливанию, т.е. «бесконечному» повторению цикла. Такие ошибки возникают при неверном задании условия в операторах цикла с предусловием и постусловием или неверном задании значений переменных и констант, используемых в операторе цикла с параметром. Выявить также семантические ошибки можно путем задания тестовых данных на этапе выполнения программы и вывода контрольных сообщений, показывающих, как изменяются переменные, формирующие условие. При этом вывод контрольных значений выполняется перед выполнением оператора цикла, в цикле и после оператора цикла.

 

Индивидуальные задания

1. Для получения практических навыков по использованию операторов цикла предлагается составить программу на языке С++ для решения по одной из задач, приведенных в таблице 2 и 3. В программе необходимо предусмотреть ввод исходных данных и вывод результата, в том числе и количество повторений цикла. Необходимо также использовать операторы вывода, контролирующие правильность выполнения цикла.

Целью решения задач, приведенных в табл. 2, является вычисление заданной функции с относительной погрешностью Eps путем вычислений указанного бесконечного ряда. Решение необходимо получить для пяти наборов исходных данных. Величину Eps нужно изменять в диапазоне от 1Е-2 до 1Е-30 при одном значении аргумента X. Кроме суммы ряда надо вывести количество учтённых слагаемых. Для проверки правильности вычислений сравнить значение полученной суммы ряда со значением библиотечной функции.

Вычисление суммы бесконечного ряда выполняется по рекуррентным формулам: в цикле с постусловием к текущему значению суммы прибавляется значение очередного слагаемого. Затем увеличивается номер слагаемого и рекуррентно вычисляется следующее слагаемое как функция от очередного слагаемого и номера следующего слагаемого. И этот цикл повторяется до достижения требуемой точности, когда модуль отношения следующего слагаемого к накопленной сумме станет меньше заданной погрешности Eps.

 

Таблица 2

Номер Функция Ряд Функция библиотеки cmath Ограничение, ед. измерения
  e^x 1+x+x^2/2!+x^3/3!+... exp(x) x – любое
  Sin(x) x-x^3/3!+x^5/5!-x^7/7!+... sin(x) x – любое, радианы
  Cos(x) 1-x^2/2!+x^4/4!-x^6/6!+... cos(x) x – любое, радианы
  ArcTg(x) x-x^3/3+x^5/5-x^7/7+... atan(x) -1 < X < 1, радианы
  Ln(1+x) x-x^2/2+x^3/3-x^4/4+... log(1+x) -1 < X < 1
  SH(x) x+x^3/3!+x^5/5!+x^7/7!+... sinh(x) x – любое
  CH(x) 1+x^2/2!+x^4/4!+x^6/6!... cosh(x) x – любое

Примечания:

- "^" - возведение в степень, "!" - факториал.

- документация на функции cmath – https://www.cplusplus.com/reference/cmath/

 

Словесный алгоритм подсчёта суммы расписывается подробно следующими пунктами (или действиями):

1. Задать начальные значения переменным: сумма = 0, слагаемое = 1 или Х (табл. 2), номер слагаемого = 0 или 1;

2. К сумме добавить очередное слагаемое;

3. Посчитать номер следующего слагаемого (+1 или +2);

4. Посчитать следующее слагаемое, имея очередное и номер следующего (разделите следующее слагаемое на предыдущее и получите требуемый множитель);

5. Повторять п. 2-4 до достижения требуемой точности.

 

2. При решении задач, приведенных в табл. 3, необходимо вычислить сумму или произведение значений функции, используя цикл с параметром. Исходными данными являются количество слагаемых (сомножителей) N, аргумент X и погрешность вычисления значения функции, заданная константой 1Е-10. Величину N изменять в диапазоне от 0 до 10, X – разумные, легко вычисляемые значения. Значение самой функции должно вычисляться через бесконечный ряд по формулам табл. 2. Для контроля необходимо запрограммировать вычисление суммы или произведения с использованием библиотечной подпрограммы.

Во всех программах предусмотреть контроль допустимости значений входных данных.

 

Таблица 3

Номер Вычислить (i = 1..n): F(x,i)
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. Сумму(F(x,i)) Сумму(F(x,i)) Сумму(F(x,i)) Сумму(F(x,i)) Сумму(F(x,i)) Сумму(F(x,i)) Сумму(F(x,i)) Произведение(F(x,i)) Произведение(F(x,i)) Произведение(F(x,i)) Произведение(F(x,i)) Произведение(F(x,i)) Произведение(F(x,i)) Sin(i*x) Cos(i*x) Sin(x/i) Cos(x/i) е^(x/i) Ln(i*x) Ln(x/i) Sin(i*x) Cos(i*x) Sin(x/i) е^(x/i) Ln(i*x) Ln(x/i)

 

Подготовка к работе

1. Изучить описание лабораторной работы.

2. Проанализировать работу программы TEST3A и частично заполнить табл. 1.

3. Разработать ГСА собственной программы. Номер задания определяется номером по списку.

4. По ГСА написать собственную программу и заготовить таблицу с исходными данными для проверки ее правильности (пять строк).

5. Заготовить в письменном виде отчет по лабораторной работе.

 

Порядок выполнения работы

1.Выполнить программу TEST3A с различными исходными данными и сравнить результаты работы программы с результатами ручной прокрутки путем заполнения табл. 1.

2. Ввести собственную программу, проверяя ее правильность ([ F9 ], [ F11 ]) после написания каждого оператора. Получить решение при различных исходных данных (0, 0.5, 10, 1Е1, 1Е-10, 1Е-20,1Е-30). Записать в отчет.

Содержание отчета

1. Титульный лист.

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

3. Индивидуальное задание.

4. Материалы в соответствии с подготовкой к работе (п. 2-5).

5. Заполненная таблица входных и выходных данных программы TEST3A.

6. Таблица сообщений собственной программы при заданных значениях входных переменных, проверяющих ограничения и допустимые значения данных.

 

Пример программы

Задание. Найти произведение функций обратного гиперболического тангенса arth(1/i*x) для значений i от 1 до n, -1<x<1.

arth x = x + x^3/3 + x^5/5 + x^7/7 + …

 

// подсчёт суммы ряда

// и вычисление произведения (arth(x,i))

#include <iostream>

#include <cmath>

#include <iomanip>

 

using namespace std;

 

int main ()

{

// Произведение функций и аргумент

float MulF, X;

// Параметр цикла и количество сомножителей

int I, N;

 

cout << "Задайте аргумент и число сомножителей: ";

cin >> X >> N;

 

// Произведение значений библиотечной функции

MulF = 1;

for (I = 1; I <= N; I++) {

cout << "\nI="<<I<<" 1.0/I*X="<<1.0/I*X;

MulF = MulF * atanh(1.0/I*X);

}

cout << "\nПроизведение atanh(1/i*x)=" << MulF;

 

// Вычисление произведения arth по бесконечному ряду

// Для ряда: сумма, слагаемое, аргумент, погрешность

float SumR, AddR, X_R, Eps;

// Номер слагаемого ряда

int N_R;

 

cout << "\n\nВведите погрешность: ";

cin >> Eps;

MulF = 1;

for (I = 1; I < N+1; I++) {

// Из выражения arth(X_R)=arth(1/I*X) аргумент ряда =

X_R = X/I;

 

// Вычисление arth для конкретного значения X_R

// Начальные значения переменных

SumR = 0; AddR = X_R; N_R = 1;

// Повторять до получения требуемой точности

do {

SumR = SumR+AddR; // Частичная сумма

N_R = N_R+1; // Номер следующего слагаемого

// Следующее слагаемое, выраженное через предыдущее

AddR = AddR*pow(X_R,2)/(2*N_R+1);

} while (abs(AddR/SumR) >= Eps);

cout << "\nЧисло слагаемых=" << N_R << " для аргумента X_R=" << X_R;

 

// Накарливаем произведение arth

MulF = MulF*SumR;

}

 

cout << "\nПроизведение atanh(x/i) через бесконечный ряд = " << MulF;

cin.get();

 

return 0;

}

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2019-12-19 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: