Лабораторная работа №5 Операторы цикла в языке С++ 1. Цель работы Целью лабораторной работы является получение практических навыков в работе с операторами цикла языка C++. 2. Темы для предварительной проработки Операторы цикла языка C++. Вложенные циклы. Условный оператор языка C++. 3. Задание для выполнения Для функции Y = f(X), график которой приведен в Вашем индивидуальном задании, вывести на экран значения Y для Х = 0, 0.25, 0.5, ... 19.75. Получить на экране график функции средствами текстового режима. 4. Варианты индивидуальных заданий Вариант 1 Вариант 2 Вариант 3 Вариант 4 Вариант 5 Вариант 6 1 Вариант 7 Вариант 8 Вариант 9 Вариант 10 Вариант 11 Вариант 12 2 Вариант 13 Вариант 14 Вариант 15 Вариант 16 Вариант 17 Вариант 18 Вариант 19 3 Вариант 20 Вариант 21 Вариант 22 Вариант 23 Вариант 24 Вариант 25 Вариант 26 Вариант 27 4 Вариант 28 Вариант 29 Вариант 30 5. Пример решения задачи (вариант 30) 5.1. Разработка алгоритма решения. 5.1.1. Общий метод решения Из приведенного в индивидуальном задании графика функции видно, что функция является периодической, с периодом 4. В заданный интервал вкладываются 5 периодов функции. Так что, программа может содержать в себе цикл, в котором 5 раз будут выполняться одни и те же вычисления. В каждой итерации этого цикла должны перебираться значения x от 0 до 3.75 с шагом 0.25, т.е., должен быть вложенный цикл. В каждой итерации вложенного цикла вычисляется значение y для текущего x и выводятся результаты. Анализ приведенного графика показывает, что каждый период его состоит из трех частей: на отрезке 0<=x<=1 график является прямой, на отрезке 1<=x<=3 - дугой, а на отрезке 3<=x<=4 другой прямой. Следовательно, во вложенном цикле должно быть разветвление, в котором определяется текущее значение x и обеспечиваются вычисления для первого, второго или третьего случая. 5.1.2. Вычисление функции на отрезке 0 - 1 На этом отрезке функция является функцией прямой. Формула прямой: y=ax+b. Для этого случая a=2, b=-1. Итак, окончательная формула для отрезка 0<=x<=1 такая: y=2x-1 5.1.3. Вычисление функции на отрезке 1 - 3 На этом отрезке функция является частью окружности. Формула окружности: (x-x0)2+(yy0)2=R2, где (x0, y0) - координаты центра окружности, а R - радиус. Отсюда y можно определить как: . В нашем случае R=1, а координаты центра - (2, 1). Извлечение квадратного корня дает два значения - положительное и отрицательное, в нашем случае используется только нижняя полуокружность, так что следует брать только отрицательное значение. Окончательная формула для отрезка 1<=x<=3 такая: y=2-((1-(x-2)2) 5.1.4. Вычисление функции на отрезке 3 - 4 Для прямой на этом отрезке a=-2, b=7, окончательная формула: y=7-2x 5.1.5. Алгоритм вывода результатов в псевдографической форме В каждой итерации внутреннего цикла мы получает одну ординату графика. Следовательно, для представления результата в псевдографической форме будет удобно развернуть график на 90о и в каждой строке экрана отображать значения x, y и символ, который изображает одну точку графика, смещение этого символа в строке будет пропорционально значению ординаты. Для отображения этого символа с необходимым смещением нужно преобразовать ординату в 5 целое число (с масштабированием к размеру строки), это число будет количеством пробелов, которое нужно вывести в строке перед символом-"точкой". В каждый период функции вкладывается 16 итераций внутреннего цикла, т.е. на экран будет выведено 16 строк на период. Целесообразно после вывода каждого периоду (который целиком помещается на экране) делать остановку в программе до команды оператора на продолжение. 5.1.6. Схема алгоритма Схема алгоритма показана на рисунке ниже. 6 5.2. Определение переменных программы Для реализации алгоритма понадобятся такие переменные: n - параметр внешнего цикла, для него достаточно короткого целого значения: short n; x - параметр внутреннего цикла и одновременно - текущее значение абсциссы графика. Хотя его точность невелика, объявим его как double, в соответствии с общим стилем программирования на С. double x; y - текущее значение ординаты графика: double y; h - смещение в строке символа, который означает точку графика. Поскольку смещение не может превышать 80 (размер строки экрана), для этой переменной достаточно будет короткого целого: short h; 5.3. Разработка текста программы Начинаем разработку текста программы с заголовка главной функции: void main() Далее открывается тело функции, и в него включаются объявления переменных (см. п.5.2). Кодовая часть программы начинается в соответствии со схемой алгоритма (блок 2) оператором-заголовком внешнего цикла. Это типичный цикл со счетчиком, он реализуется оператором: for (n=0; n<5; n++) { Так как в теле цикла содержится несколько отдельных действий, значит, будет несколько операторов, тело цикла берется в операторные скобки. В теле цикла прежде всего печатается заголовок таблицы (блок 3) операторами: cout << "| x | y |" << endl; cout << "|-------|------------|" << endl; После этого открываем внутренний цикл (блок 4). Параметр этого цикла - значение абсциссы x - принимает значения от 0 до 3.75 с шагом 0.25: for (x=0; x<4; x+=0.25) { Блок 5 схемы алгоритма (проверка попадания на первый отрезок) реализуется условным оператором: if (x<1) В случае выполнения этого условия, значение абсциссы вычисляется (блок 7) по уравнению для первой прямой: y=2*x-1; Если же предыдущее условие не выполняется, блок 6 схемы алгоритма (проверка попадания на второй отрезок) реализуется условным оператором: else if (x<3) В случае выполнения этого условия, значение абсциссы вычисляется (блок 8) по уравнению для полуокружности: y=1-sqrt(1-(x-2)*(x-2)); В этом выражении для возведения в степень 2 применяется умножение. Функция sqrt() описана в файле math.h, так что включаем этот файл в начало программы: #include <math.h> Если же и это условие не выполняется, то мы имеем попадание на третий отрезок, и значение абсциссы вычисляется (блок 9) по уравнению для второй прямой: else y=7-2*x; Во внутреннем цикле мы выполняем вычисления для одного периода функции, но внешний цикл выполняется у нас 5 раз. Реальное значение абсциссы с учетом внешнего цикла составляет x+4n. Теперь, когда мы имеем абсциссу и ординату графика, можем выводить строку выходных данных (блок 10). Сперва выводим строку таблицы: cout << "| " << setprecision(2) << setw(5) << x+n*4 << " | " << setprecision(7) << setw(10) << y << " |"; 7 Следующий шаг - вывод в той же строку точки графика. После вывода строки таблицы в строке экрана осталось 57 свободных знакомест. На этом пространстве нам нужно показать значения y от -1 до +1. Если мы возьмем коэффициент масштабирования 10, то амплитуда графика составит 20 знакомест - достаточно для наглядного его представления. Масштабирование значения ординаты выполняется оператором: h=(y+1)*10; Выбранное значение коэффициента масштабирования - 10 - может быть изменено при отладке. При выполнении последнего оператора мы теряем дробную часть. Поскольку среди библиотечных функций языка C нет функции точного округления, мы выполняем такое округление сами: if (y-1-h*10>0.5) h++; Далее в строку экрана выводится (блоки 12-13) требуемое количество пробелов. В следующем цикле полученное ранее значение h работает как счетчик на вычитание. for (; h>0; h--) cout << " "; а потом выводится символ '*' и происходит переход на новую строку экрана: cout << "*" << endl; На этом заканчивается внутренний цикл. После выхода из внутреннего цикла мы выводим сообщение оператору: cout << Rus("Нажмите любую клавишу...") << endl; И ждем нажатия клавиши: getch(); На этом закрывается внешний цикл, а потом и тело функции main(). Полный текст программы приведен ниже. /****************************************************/ /* Лабораторная работа №5 */ /* Вычисление значений периодической функции */ /* Пример выполнения. Вариант №30. */ /****************************************************/ #include <vcl.h> #include <conio.h> #include <iostream.h> #include <iomanip.h> #include <math.h> char* Rus(const char* text); void main() { short n; /* параметр внешнего цикла */ double x, y; /* абсцисса и ордината графика */ short h; /* позиция точки на экране */ cout << setiosflags(ios::fixed); /* внешний цикл - для 5 периодов */ for (n=0; n<5; n++) { /* вывод заголовка таблицы */ cout << "| x | y |" << endl; cout << "|-------|------------|" << endl; /* внутренний цикл для одного периода */ for (x=0; x<4; x+=0.25) { /* 1-й отрезок */ if (x<1) y=2*x-1; /* 2-й отрезок */ else if (x<3) y=1-sqrt(1-(x-2)*(x-2)); /* 3-й отрезок */ else y=7-2*x; /* вывод строки таблицы */ cout << "| " << setprecision(2) << setw(5) << x+n*4 << " | " << setprecision(7) << setw(10) << y << " |"; 8 /* определение позиции точки */ h=(y+1)*10; if (y-1-h*10>0.5) h++; /* вывод точки графика */ for (; h>0; h--) cout << " "; cout << "*" << endl; } /* конец внутреннего цикла */ /* пауза до команды оператора */ cout << Rus("Нажмите любую клавишу...") << endl; getch(); } /* конец внешнего цикла */ } /* конец программы */ char bufRus[256]; char* Rus(const char* text) { CharToOem(text,bufRus); return bufRus; } 5.4. Отладка программы Форма вывода в приведенной программе такая, что нет настоятельной необходимости применять при отладке пошаговый режим. Однако логический план отладки следует составить поэтапным: убедиться в правильной организации внешнего и внутреннего циклов; убедиться в правильной работе цепочки условий, которые определяют отрезок; убедиться в правильном вычислении значения ординаты на первом отрезке (только по числовым значениям); на примере первого отрезка убедиться в правильном выводе графика; убедиться в правильном вычислении значения ординаты на втором отрезке; убедиться в правильном вычислении значения ординаты на третьем отрезке. 5.5. Результаты работы программы Мы приводим только часть результатов, полученных на экране при работе программы (для одного периода функции). Остальные результаты повторяют приведенные с другими значениями x. | x | y | |-------|------------| | 0.00 | -1.0000000 |* | 0.25 | -0.5000000 | | 0.50 | 0.0000000 | | 0.75 | 0.5000000 | | 1.00 | 1.0000000 | | 1.25 | 0.3385622 | | 1.50 | 0.1339746 | | 1.75 | 0.0317542 | | 2.00 | 0.0000000 | | 2.25 | 0.0317542 | | 2.50 | 0.1339746 | | 2.75 | 0.3385622 | | 3.00 | 1.0000000 | | 3.25 | 0.5000000 | | 3.50 | 0.0000000 | | 3.75 | -0.5000000 | Нажмите клавишу Enter... . . . * * * * * * * * * * * * * * * 9 10