← До переліку лабораторних робіт
Лабораторна робота №2. Розгалужені обчислювальні процеси
Варіант 19 · Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11 · C++17, g++
1. Мета роботи
- Вивчити особливості розгалужених обчислювальних процесів.
- Опанувати технологію використання логічних операторів.
2. Умова задачі
Завдання 1
Визначити значення функції залежно від значення її аргументу, який вводиться з клавіатури (таблиця 2.1, варіант 19):
| 4 − x², якщо 0 < x < 4
| 0, якщо x = 0
f(x) = | x³, якщо x < 0
| 1, якщо x > 4
Завдання 2
Увести з клавіатури дійсні числа x, y. Визначити, чи належить точка з координатами (x, y) зафарбованій частині площини (таблиця 2.2, варіант 19).
3. Аналіз задачі та теоретичне обґрунтування
Завдання 1
Умови варіанта є діапазонними (нерівності над дійсним числом), тому оператор
switch тут незастосовний: за синтаксисом мови вираз-селектор не може належати
до дійсного типу. Використано ланцюжок if … else if … else. Гілки
впорядковано так, щоб кожна наступна перевірка виконувалась лише для аргументів, які не
потрапили в попередні: спочатку x < 0, потім x == 0, далі
x < 4, і нарешті x > 4. Це усуває потребу в складених
умовах виду 0 < x && x < 4 і зменшує кількість порівнянь.
Окремо слід зазначити прогалину в умові варіанта: інтервали задано строгими нерівностями
0 < x < 4 та x > 4, тому точка x = 4 не
покривається жодною з чотирьох гілок. Довільно доозначувати функцію в цій точці
некоректно, тому програма повідомляє, що функцію не визначено, — це відповідає умові
буквально.
Завдання 2
На рисунку варіанта подано дві зафарбовані фігури.
Фігура 1 — кільце. Зафарбовано частину площини між двома концентричними колами з центром у початку координат: внутрішній радіус 0,5, зовнішній 1. Оскільки на рисунку межі суцільні, вони належать зафарбованій частині:
0,5 ≤ √(x² + y²) ≤ 1
Фігура 2 — ромб із вершинами (−0,5; 0), (0; 1), (0,5; 0), (0; −1). Ромб із півдіагоналями a = 0,5 по осі Ox та b = 1 по осі Oy описується канонічною нерівністю:
|x| / 0,5 + |y| / 1 ≤ 1, тобто 2·|x| + |y| ≤ 1
Рисунок варіанта подає обидві фігури в окремих системах координат і не вказує однозначно,
чи мається на увазі одна з них, чи їх об'єднання. Тому програма не робить довільного
вибору за умову, а обчислює належність окремо до кожної фігури та до їх об'єднання;
потрібний режим користувач обирає в меню. Меню реалізовано оператором
switch — це поліваріантний вибір за цілим селектором, для якого
switch є природною конструкцією.
Порівняння дійсних чисел виконується з допуском EPS = 1e-9: точка, що лежить
точно на межі фігури, має зараховуватись як така, що належить фігурі, а пряме порівняння
<= для результату sqrt() цього не гарантує через похибку
округлення.
Рекомендована література (зі списку методичних вказівок): Ковалюк Т.В. Алгоритмізація та програмування. – Львів.: «Магнолія 2006», 2024. – 400 с.; Deitel P., Deitel H. C++ How to Program. Pearson Education, Inc. Hoboken, New Jersey. 2017. – 3015 p.
4. Блок-схема алгоритму
Схеми побудовано з текстів програм за допомогою rombik (rombik.app) відповідно до ДСТУ 19.701-90 (ISO 5807).
5. Текст програми
Завдання 1 — task1.cpp
/*==============================================================================
Лабораторна робота №2. Завдання 1. Варіант 19.
Тема: розгалужені обчислювальні процеси.
Умова: визначити значення функції залежно від значення її аргументу,
що вводиться з клавіатури (таблиця 2.1, варіант 19):
| 4 - x^2, 0 < x < 4
| 0, x = 0
f(x) = | x^3, x < 0
| 1, x > 4
Зауваження щодо області визначення: умови таблиці не покривають точку
x = 4 (інтервал заданий строгими нерівностями 0 < x < 4 та x > 4).
Тому x = 4 обробляється як точка, в якій функцію не визначено, — про це
виводиться окреме повідомлення, а не довільно домальоване значення.
Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11.
Компілятор: g++ -std=c++17
==============================================================================*/
#include <iostream>
/* Код результату обчислення функції: чи визначено її в заданій точці. */
enum FuncStatus { FUNC_OK, FUNC_UNDEFINED };
/*------------------------------------------------------------------------------
evaluate — обчислити значення кусково-заданої функції f(x).
Параметри:
x [вхідний] — аргумент функції;
result [вихідний] — адреса змінної для значення функції;
заповнюється лише при поверненні FUNC_OK.
Повертає: FUNC_OK — функцію визначено, значення записано в *result;
FUNC_UNDEFINED — функцію не визначено в точці x (випадок x = 4).
Гілки реалізовано вкладеною конструкцією if ... else if ... else, оскільки
умови є діапазонними: оператор switch тут незастосовний, бо його
вираз-селектор не може належати до дійсного типу.
------------------------------------------------------------------------------*/
FuncStatus evaluate(double x, double *result)
{
if (x < 0.0) {
*result = x * x * x;
} else if (x == 0.0) {
*result = 0.0;
} else if (x < 4.0) {
*result = 4.0 - x * x;
} else if (x > 4.0) {
*result = 1.0;
} else {
return FUNC_UNDEFINED; /* залишається єдиний випадок x = 4 */
}
return FUNC_OK;
}
/*------------------------------------------------------------------------------
branchName — текстова назва гілки, яку задіяно для заданого аргументу.
Використовується для протоколювання: показує, яка саме умова спрацювала.
Параметри: x [вхідний] — аргумент функції.
Повертає : рядок-константу з описом гілки.
------------------------------------------------------------------------------*/
const char *branchName(double x)
{
if (x < 0.0)
return "x < 0 -> f(x) = x^3";
if (x == 0.0)
return "x = 0 -> f(x) = 0";
if (x < 4.0)
return "0 < x < 4 -> f(x) = 4 - x^2";
if (x > 4.0)
return "x > 4 -> f(x) = 1";
return "x = 4 -> функцію не визначено";
}
/*------------------------------------------------------------------------------
readArgument — прочитати дійсне число з контролем коректності введення.
Параметри: x [вихідний] — адреса змінної для аргументу функції.
Повертає : true — число прочитано; false — вхідні дані вичерпано.
------------------------------------------------------------------------------*/
bool readArgument(double *x)
{
std::cout << "Уведіть аргумент x = ";
while (!(std::cin >> *x)) {
if (std::cin.eof())
return false;
std::cin.clear(); /* зняти прапорець помилки */
std::cin.ignore(1024, '\n'); /* очистити буфер клавіатури */
std::cout << "Помилка: очікується дійсне число. Повторіть: ";
}
return true;
}
/*------------------------------------------------------------------------------
Головна функція. Організовує введення аргументу, виклик обчислення
та виведення результату.
Локальні змінні:
x — аргумент функції, введений з клавіатури;
y — обчислене значення функції;
status — ознака визначеності функції в точці x.
------------------------------------------------------------------------------*/
int main()
{
std::cout << "Лабораторна робота №2, завдання 1 (варіант 19)\n"
"Виконав: студент групи ІПЗ-11 Одарчук Олексій\n"
"Обчислення кусково-заданої функції f(x):\n"
" 4 - x^2, якщо 0 < x < 4\n"
" 0, якщо x = 0\n"
" x^3, якщо x < 0\n"
" 1, якщо x > 4\n"
<< std::endl;
double x = 0.0;
if (!readArgument(&x)) {
std::cout << "\nВхідні дані вичерпано." << std::endl;
return 1;
}
double y = 0.0;
const FuncStatus status = evaluate(x, &y);
/* Дійсні числа виводяться у фіксованому форматі з шістьма знаками. */
std::cout.setf(std::ios::fixed);
std::cout.precision(6);
std::cout << "\nАргумент: x = " << x << std::endl;
std::cout << "Гілка: " << branchName(x) << std::endl;
if (status == FUNC_UNDEFINED) {
std::cout << "Результат: функцію не визначено в точці x = 4 "
"(умова варіанта не покриває цю точку)."
<< std::endl;
return 2;
}
std::cout << "Результат: f(" << x << ") = " << y << std::endl;
return 0;
}
Завдання 2 — task2.cpp
/*==============================================================================
Лабораторна робота №2. Завдання 2. Варіант 19.
Тема: розгалужені обчислювальні процеси.
Умова: увести з клавіатури дійсні числа x, y. Визначити, чи належить точка
з координатами (x, y) зафарбованій частині площини
(таблиця 2.2, варіант 19).
Опис фігур із рисунка варіанта.
Фігура 1 — кільце: зафарбовано частину площини між двома концентричними
колами з центром у початку координат, внутрішній радіус 0,5, зовнішній 1.
Межі кіл на рисунку суцільні, тобто належать зафарбованій частині:
0,5 <= sqrt(x^2 + y^2) <= 1.
Фігура 2 — ромб із вершинами (-0,5; 0), (0; 1), (0,5; 0), (0; -1).
Канонічне рівняння ромба з півдіагоналями a = 0,5 (по осі Ox)
та b = 1 (по осі Oy):
|x| / 0,5 + |y| / 1 <= 1, тобто 2*|x| + |y| <= 1.
Оскільки на рисунку варіанта подано дві фігури в окремих системах координат,
програма визначає належність точки кожній фігурі окремо та їх об'єднанню.
Режим перевірки обирає користувач у меню (оператор switch).
Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11.
Компілятор: g++ -std=c++17
==============================================================================*/
#include <iostream>
#include <cmath>
/* Півдіагоналі ромба та радіуси кільця — константи умови варіанта. */
const double R_INNER = 0.5; /* внутрішній радіус кільця */
const double R_OUTER = 1.0; /* зовнішній радіус кільця */
const double RHOMB_A = 0.5; /* півдіагональ ромба по осі Ox */
const double RHOMB_B = 1.0; /* півдіагональ ромба по осі Oy */
/* Допуск для порівняння дійсних чисел: точка на самій межі фігури має
зараховуватись як така, що належить фігурі, попри похибку округлення. */
const double EPS = 1e-9;
/*------------------------------------------------------------------------------
inRing — чи належить точка кільцю 0,5 <= r <= 1.
Параметри: x, y [вхідні] — координати точки.
Повертає : true — точка належить кільцю (разом з межами).
Локальні змінні:
r — відстань від початку координат до точки.
------------------------------------------------------------------------------*/
bool inRing(double x, double y)
{
const double r = std::sqrt(x * x + y * y);
return r >= R_INNER - EPS && r <= R_OUTER + EPS;
}
/*------------------------------------------------------------------------------
inRhombus — чи належить точка ромбу |x|/a + |y|/b <= 1.
Параметри: x, y [вхідні] — координати точки.
Повертає : true — точка належить ромбу (разом з межами).
------------------------------------------------------------------------------*/
bool inRhombus(double x, double y)
{
return std::fabs(x) / RHOMB_A + std::fabs(y) / RHOMB_B <= 1.0 + EPS;
}
/*------------------------------------------------------------------------------
readChoice — прочитати номер пункту меню (1..3) з контролем введення.
Параметри: choice [вихідний] — адреса змінної для номера пункту.
Повертає : true — номер прочитано; false — вхідні дані вичерпано.
------------------------------------------------------------------------------*/
bool readChoice(int *choice)
{
std::cout << "Оберіть фігуру (1..3): ";
while (!(std::cin >> *choice) || *choice < 1 || *choice > 3) {
if (std::cin.eof())
return false;
std::cin.clear(); /* зняти прапорець помилки */
std::cin.ignore(1024, '\n'); /* очистити буфер клавіатури */
std::cout << "Помилка: потрібне число 1, 2 або 3. Повторіть: ";
}
return true;
}
/*------------------------------------------------------------------------------
readPoint — прочитати координати точки з контролем коректності введення.
Параметри: x, y [вихідні] — адреси змінних для координат точки.
Повертає : true — координати прочитано; false — вхідні дані вичерпано.
------------------------------------------------------------------------------*/
bool readPoint(double *x, double *y)
{
std::cout << "Уведіть координати точки x та y: ";
while (!(std::cin >> *x >> *y)) {
if (std::cin.eof())
return false;
std::cin.clear();
std::cin.ignore(1024, '\n');
std::cout << "Помилка: очікуються два дійсних числа. Повторіть: ";
}
return true;
}
/*------------------------------------------------------------------------------
yesNo — слово «так» або «ні» для логічного значення.
Параметри: value [вхідний] — логічне значення.
Повертає : рядок-константу «так» або «ні».
------------------------------------------------------------------------------*/
const char *yesNo(bool value)
{
if (value)
return "так";
return "ні";
}
/*------------------------------------------------------------------------------
Головна функція. Виводить меню вибору фігури, читає координати точки
та повідомляє результат перевірки.
Локальні змінні:
choice — номер пункту меню, обраний користувачем;
x, y — координати точки;
ring — ознака належності точки кільцю;
rhomb — ознака належності точки ромбу;
belongs — ознака належності точки обраній фігурі;
figure — назва обраної фігури для повідомлення.
------------------------------------------------------------------------------*/
int main()
{
std::cout << "Лабораторна робота №2, завдання 2 (варіант 19)\n"
"Виконав: студент групи ІПЗ-11 Одарчук Олексій\n"
"Належність точки зафарбованій частині площини\n\n"
" 1 - кільце 0,5 <= sqrt(x^2 + y^2) <= 1\n"
" 2 - ромб |x|/0,5 + |y|/1 <= 1\n"
" 3 - об'єднання обох фігур\n"
<< std::endl;
int choice = 0;
if (!readChoice(&choice)) {
std::cout << "\nВхідні дані вичерпано." << std::endl;
return 1;
}
double x = 0.0, y = 0.0;
if (!readPoint(&x, &y)) {
std::cout << "\nВхідні дані вичерпано." << std::endl;
return 1;
}
const bool ring = inRing(x, y);
const bool rhomb = inRhombus(x, y);
/* Дійсні числа виводяться у фіксованому форматі з чотирма знаками. */
std::cout.setf(std::ios::fixed);
std::cout.precision(4);
std::cout << "\nТочка: x = " << x << ", y = " << y << std::endl;
std::cout << " відстань від початку координат r = " << std::sqrt(x * x + y * y)
<< std::endl;
std::cout << " значення |x|/0,5 + |y|/1 = "
<< std::fabs(x) / RHOMB_A + std::fabs(y) / RHOMB_B << std::endl;
bool belongs = false;
const char *figure;
/* Поліваріантний вибір: кожна гілка завершується оператором break,
інакше керування «провалилося» б у наступну гілку. */
switch (choice) {
case 1:
belongs = ring;
figure = "кільцю";
break;
case 2:
belongs = rhomb;
figure = "ромбу";
break;
case 3:
belongs = ring || rhomb;
figure = "об'єднанню кільця та ромба";
break;
default:
std::cout << "Неіснуючий пункт меню." << std::endl;
return 2;
}
if (belongs)
std::cout << "\nНалежність " << figure << ": ТАК — точка у зафарбованій частині"
<< std::endl;
else
std::cout << "\nНалежність " << figure
<< ": НІ — точка поза зафарбованою частиною" << std::endl;
std::cout << "\nДовідково: кільце - " << yesNo(ring) << ", ромб - " << yesNo(rhomb)
<< std::endl;
return 0;
}
6. Результати виконання роботи
Компіляція: make (g++ -std=c++17, прапорці
-Wall -Wextra -pedantic -O2). Попереджень компілятора немає.
Нижче наведено екранні копії повних прогонів програм: кожна починається з запуску програми, містить усе введення з клавіатури й увесь вивід до завершення роботи. Прогін, що не вміщується на один екран, подано кількома послідовними частинами. Протоколи всіх прогонів, зокрема додаткових наборів вхідних даних, винесено окремими файлами за посиланнями.
Повний протокол виконання (task1.txt) — повний протокол, 104 рядків
Повний протокол виконання (task2.txt) — повний протокол, 159 рядків
7. Аналіз достовірності результатів
Достовірність результатів перевірено аналітично: значення функції обчислено вручну для кожної гілки, а належність точок фігурам — підстановкою координат у нерівності кільця 0,5 ≤ √(x²+y²) ≤ 1 та ромба |x|/0,5 + |y|/1 ≤ 1. Для кожної контрольної величини поруч із розрахунком наведено результат програми.
Завдання 1 — перевірка кожної гілки
| x | Задіяна гілка | Аналітичний розрахунок | Результат програми |
|---|---|---|---|
| −2 | x < 0 | (−2)³ = −8 | −8,000000 |
| −0,5 | x < 0 | (−0,5)³ = −0,125 | −0,125000 |
| 0 | x = 0 | 0 | 0,000000 |
| 2 | 0 < x < 4 | 4 − 2² = 0 | 0,000000 |
| 3,9 | 0 < x < 4 | 4 − 15,21 = −11,21 | −11,210000 |
| 4 | — | не визначено умовою | повідомлення про невизначеність |
| 7 | x > 4 | 1 | 1,000000 |
Задіяно всі чотири гілки функції та випадок невизначеності; усі обчислені значення збігаються з ручним розрахунком.
Завдання 2 — перевірка на характерних точках
| Точка (x; y) | r = √(x²+y²) | |x|/0,5 + |y| | Кільце (аналітично) | Ромб (аналітично) | Результат програми |
|---|---|---|---|---|---|
| (0,8; 0) | 0,8000 | 1,6000 | так (0,5 ≤ 0,8 ≤ 1) | ні (1,6 > 1) | кільце — так, ромб — ні |
| (0,1; 0,1) | 0,1414 | 0,3000 | ні (0,1414 < 0,5) | так (0,3 ≤ 1) | кільце — ні, ромб — так |
| (0; 0,9) | 0,9000 | 0,9000 | так | так | кільце — так, ромб — так |
| (0,9; 0,9) | 1,2728 | 2,7000 | ні (> 1) | ні | кільце — ні, ромб — ні |
| (0,5; 0) — межа кільця | 0,5000 | 1,0000 | так (точно на межі) | так (точно на межі) | кільце — так, ромб — так |
| (0,25; 0,5) — межа ромба | 0,5590 | 1,0000 | так | так (точно на межі) | кільце — так, ромб — так |
Дві останні точки перевіряють саме граничні випадки: (0,5; 0) лежить на внутрішньому колі кільця, (0,25; 0,5) — на стороні ромба. Обидві зараховано як належні, що відповідає суцільним межам на рисунку варіанта і підтверджує коректність роботи допуску EPS.
8. Висновки
- Вивчено розгалужені обчислювальні процеси; реалізовано вибір із двох та багатьох альтернатив.
-
Застосовано ланцюжок
if … else if … elseдля діапазонних умов над дійсним аргументом і операторswitchдля поліваріантного вибору за цілим селектором. -
Опрацьовано логічні операції
&&та||у складених умовах належності точки фігурам. -
Виявлено та коректно оброблено прогалину в умові варіанта: точку
x = 4не покрито жодною гілкою, тому функція в ній вважається невизначеною. - Враховано специфіку порівняння дійсних чисел: належність межі фігури визначається з допуском, а не прямим порівнянням.
- Обидва завдання варіанта виконано в повному обсязі.