В примере выполнения лабораторного задания по теме «Программирование алгоритмов вложенных циклических структур» решается задача формирования таблицы значений сложной функции с условием
x2 +y2, если 0<x<1 и 0<y<1;
z(x,y)=
x+y, в противном случае
при изменении x на отрезке [ a; b ] с шагом h1 и y на отрезке [ c;d ] с шагом h2
(a = -1, b = 1, h1 = 0.5, c = -0.5, d = 0.5, h2 = 0.25). Кроме того, требуется найти сумму и количество положительных значений z(x,y) на этом же отрезке. Будем считать, что вещественные исходные данные и результаты вычислений имеют тип float.
Так как заданы границы отрезков и шаги изменения аргументов, то мы можем определить количества точек табуляции по каждому аргументу x и y по формулам:
n1 = [(b – a)/h1] + 1
n2 = [(d – c)/h2] + 1
где a, b, c, d – границы отрезков табуляции, h1, h2 – шаги табуляции, а квадратные скобки обозначают операцию округления в меньшую сторону результата вычисления выражения в скобках.
Так как при каждом значении аргумента x программа должна повторять вычисление функции n2 раз, а количество изменений аргумента x равно n1, то алгоритм решения задачи относится к вложенным регулярным циклам с параметрами. Общее число точек таблицы будет равно произведению n1*n2.
Для реализации задания разработаем следующие пользовательские функции:
· функция f, вычисляющая z(x,y) при заданных значениях x и y;
· функция RegCikl2, формирующая и выводящая таблицу значений z(x,y) на заданных отрезках изменения x и y, а также определяющая сумму и количество положительных значений функции;
· функция Get, выполняющая ввод исходных данных: границ отрезков [a;b] и [ c;d ], шагов табуляции h1 и h2;
· функция Put, выводящая найденные сумму и количество положительных значений z(x,y);
· главная функция main, последовательно вызывающая функции Get, RegCikl2 и Put.
Схемы алгоритмов функций f и RegCikl2 разрабатываются студентами самостоятельно.
Алгоритм вычисления сложной функции с условием f сводится в данном случае к стандартному разветвлению с двумя ветвями.
Алгоритм функции RegCikl2 подобен алгоритму Примера 7 из лекции 13, схема которого изображена на рис. 7. Он легко адаптируется к решению задачи нашего примера следующим образом:
· в первом операторе алгоритма инициализируются нулевыми значениями переменные s (сумма положительных значений функции) и k (количество положительных значений функции);
· оператор вычисления z = x2 + y2 заменяется на вызов функции f с записью результата в переменную z;
· после этого вызова организуется усеченное разветвление с проверкой знака вычисленного значения функции: если функция положительна, то к переменной s добавляется значение переменной z, а к переменной k добавляется единица.
В соответствии с заданием программные коды функций поместим в 3 раздельно компилируемых файла:
· файл GetPut.cpp, содержащий функцию ввода исходных данных и функцию вывода результатов;
· файл Calc.cpp с функциями вычислениязначенияфункции z(x,y) и построения таблицы ее значений;
· файл main.cpp с главной функцией,которая содержит только операторы вызова пользовательских функций.
Рисунок 7 - Схема алгоритма задачи Примера 7
На рис. 8 приведен программный код файла GetPut.cpp.
Функция Get предназначена для ввода исходных данных задачи: концов отрезков табулирования a, b, c, d и шагов таблицы h1, h2. Соответствующие переменные являются выходными параметрами функции, передаваемыми по ссылке.
Функция Put предназначена для вывода результатов выполнения проекта: суммы sPos и количества nPos положительных значений функции. Соответствующие переменные являются входными параметрами функции, передаваемыми по значению.
На рис. 9 приведен программный код файла Calc.cpp.
Программный код функции f тривиален. Разветвление в зависимости от значений x и y реализовано с помощью тернарной условной операции.
// файл GetPut.cpp с функциями ввода и вывода
#include <iostream>
using namespace std;
void Get(float& a, float& b, float& h1, float& c, float& d, float& h2)
{
setlocale(LC_ALL, "rus");
cout<<"Введите нижнюю границу отрезка изменения X: ";
cin>>a;
cout<<"Введите верхнюю границу отрезка изменения X: ";
cin>>b;
cout<<"Введите шаг изменения X: ";
cin>>h1;
cout<<"Введите нижнюю границу отрезка изменения Y: ";
cin>>c;
cout<<"Введите верхнюю границу отрезка изменения Y: ";
cin>>d;
cout<<"Введите шаг изменения Y: ";
cin>>h2;
}
void Put(float sPos, int nPos)
{
setlocale(LC_ALL, "rus");
cout<<endl<<"Сумма положительных значений функции: "<<sPos<<endl;
cout<<"Количество положительных значений функции: "<<nPos<<endl;
}
Рисунок 8 – программный код файла GetPut.cpp
// файл Calc.cpp
#include <iostream>
using namespace std;
float f(float x, float y);
float RegCikl2(float a, float b, float h1, float c, float d, float h2, int& nPos)
{
setlocale(LC_ALL, "rus");
int n1 = int((b-a)/h1) + 1;
int n2 = int((d-c)/h2) + 1;
float sPos = 0.0;
nPos = 0;
float x, y, z;
cout<<endl<<"Таблица значений функции"<<endl;
cout<<"\tx\ty\tz"<<endl;
x = a;
for (int i=1; i<=n1; i++)
{
y = c;
for (int j =1; j<=n2; j++)
{
z = f(x,y);
if (z > 0) {sPos+=z; nPos++;}
cout<<"\t"<<x<<"\t"<<y<<"\t"<<z<<endl;
y+=h2;
}
x+=h1;
}
return sPos;
}
float f(float x, float y)
{
return (x>0 && x<1 && y>0 && y<1)? (x*x + y*y): (x + y);
}
Рисунок 9 – программный код файла Calc.cpp
В функцию RegCikl2 в качестве входных параметров передаются по значению границы и шаг изменения аргументов. Выходным параметром, возвращаемым по ссылке, является подсчитанное количество положительных значений функции nPos. Подсчитанная функцией сумма положительных значений sPos возвращается оператором return.
Числа повторений внешнего цикла n1 и внутреннего – n2 вычисляются путем усечения результатов деления до целых значений явным преобразованием в тип int. Это позволяет избежать лишних преобразований типов данных по сравнению с использованием функции floor (см. Задание 13).
Для перебора всех сочетаний аргументов x и y организуются вложенные циклы с параметрами i и j. Очередные значения аргументов вычисляются через предыдущие путем добавления соответствующего шага.
На рис. 10 приведен программный код файла Main.cpp. В файле определены прототипы используемых функций Get, Put и RegCikl2. Тело функции main содержит определения используемых переменных и последовательные вызовы этих функций.
// файл Main.cpp
#include <iostream>
void Get(float& a, float& b, float& h1, float& c, float& d, float& h2);
void Put(float sPos, int nPos);
float RegCikl2(float a, float b, float h1, float c, float d, float h2, int& nPos);
void main()
{
float a, b, h1, c, d, h2, sPos;
int nPos;
Get(a, b, h1, c, d, h2);
sPos = RegCikl2(a, b, h1, c, d, h2, nPos);
Put(sPos, nPos);
system("PAUSE");
}
Рисунок 10 – программный код файла Main.cpp
На рис. 11 приведены результаты выполнения проекта.
Правильность вычисления табличных значений функции, а также определения суммы и количества положительных значений функции следует из непосредственной проверки результатов.
Рисунок 11 – результаты выполнения проекта