← До переліку лабораторних робіт
Лабораторна робота №1. Типи даних. Функції введення-виведення. Обчислення виразів
Варіант 19 · Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11 · C17, gcc / C++17, g++
1. Мета роботи
-
Вивчити особливості використання вбудованих типів даних:
char,int,long,short,float,double,unsigned char,unsigned int,unsigned long. - Вивчити особливості використання функцій введення-виведення.
- Навчитися застосовувати стандартні математичні функції.
2. Умова задачі
Завдання 1
За даними, введеними з клавіатури, обчислити значення виразу і вивести результат на екран (таблиця 1.7, варіант 19):
X = (A·cos²B + 1)^(1/2) · ln(C) / D
Завдання 2
Нехай число ab містить цифри a і b. Довести, що
число ab + ba ділиться на 11 (таблиця 1.8, варіант 19).
3. Аналіз задачі та теоретичне обґрунтування
Завдання 1
Вираз обчислюється безпосередньо через стандартні математичні функції заголовного файла
<math.h>: cos(), sqrt(), log().
Піднесення до степеня 1/2 реалізовано як квадратний корінь, що точніше й швидше за
pow(x, 0.5); квадрат косинуса — як добуток cosB*cosB, щоб
уникнути виклику pow.
Область визначення виразу обмежена трьома умовами, які перевіряються до обчислення:
C > 0— аргумент натурального логарифма;D ≠ 0— знаменник дробу;A·cos²B + 1 ≥ 0— підкореневий вираз.
Третя умова не є формальністю: при A < −1 і cos²B близькому
до одиниці підкореневий вираз стає від'ємним. Усі величини мають тип
double (≈15 значущих десяткових цифр), чого достатньо для задачі. Кут
B задається в радіанах, оскільки саме такий аргумент приймає
cos().
Завдання 2
Аналітичне доведення. Двоцифрове число у позиційній десятковій системі має значення:
ab = 10·a + b, ba = 10·b + a ab + ba = (10a + b) + (10b + a) = 11a + 11b = 11·(a + b)
Сума є добутком числа 11 на ціле число (a + b), отже ділиться на 11 без
остачі, причому частка дорівнює сумі цифр числа. Що й треба було довести.
Програмна частина не замінює доведення, а підтверджує його обчислювально: тотожність
перевіряється для всіх 90 двоцифрових чисел (a = 1…9, b = 0…9).
Це вичерпний перебір, тому відсутність контрприкладу є повним підтвердженням для
двоцифрового випадку.
Рекомендована література (зі списку методичних вказівок): Ковалюк Т.В. Алгоритмізація та програмування. – Львів.: «Магнолія 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.c
/*==============================================================================
Лабораторна робота №1. Завдання 1. Варіант 19.
Тема: типи даних, функції введення-виведення, обчислення виразів.
Умова: за даними, введеними з клавіатури, обчислити значення виразу
X = (A*cos^2(B) + 1)^(1/2) * ln(C) / D
та вивести результат на екран.
Метод: вираз обчислюється безпосередньо за допомогою стандартних
математичних функцій cos(), sqrt(), log() з <math.h>.
Перед обчисленням перевіряються обмеження області визначення:
C > 0 (аргумент натурального логарифма);
D != 0 (дільник);
A*cos^2(B) + 1 >= 0 (підкореневий вираз).
Введення-виведення: форматні функції scanf()/printf() з <stdio.h>
(демонстрація потокового введення-виведення — у завданні 2).
Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11.
Компілятор: gcc -std=c17
==============================================================================*/
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
/*------------------------------------------------------------------------------
readDouble — прочитати одне дійсне число з клавіатури з контролем коректності.
Параметри:
prompt [вхідний] — текст запрошення, що виводиться користувачеві;
value [вихідний] — адреса змінної, куди буде записано введене число.
Повертає: true — число успішно прочитано;
false — досягнуто кінця вхідного потоку (EOF).
Локальні змінні:
c — черговий символ, що зчитується під час очищення буфера клавіатури.
------------------------------------------------------------------------------*/
bool readDouble(const char *prompt, double *value)
{
for (;;) {
printf("%s", prompt);
/* scanf повертає кількість успішно заповнених полів,
або EOF, якщо вхідний потік вичерпано. */
int scanned = scanf("%lf", value);
if (scanned == EOF)
return false;
if (scanned == 1)
return true;
/* Введено не число: очищаємо буфер клавіатури до кінця рядка,
інакше scanf нескінченно натикатиметься на ті самі символи. */
int c;
while ((c = getchar()) != '\n' && c != EOF) {
/* пропускаємо залишок хибного рядка */
}
printf("Помилка: очікується дійсне число. Спробуйте ще раз.\n");
}
}
/*------------------------------------------------------------------------------
Головна функція. Організовує введення вихідних даних, перевірку області
визначення виразу та виведення результату.
Локальні змінні:
a, b, c, d — вихідні дані, введені з клавіатури;
cosB — проміжне значення cos(B);
radicand — підкореневий вираз A*cos^2(B) + 1;
x — шукане значення виразу.
------------------------------------------------------------------------------*/
int main()
{
double a = 0.0, b = 0.0, c = 0.0, d = 0.0;
printf("Лабораторна робота №1, завдання 1 (варіант 19)\n");
printf("Виконав: студент групи ІПЗ-11 Одарчук Олексій\n");
printf("Обчислення виразу X = sqrt(A*cos^2(B) + 1) * ln(C) / D\n");
printf("Кут B задається в радіанах, C > 0, D != 0.\n\n");
if (!readDouble("Уведіть A = ", &a))
return 1;
if (!readDouble("Уведіть B (радіани) = ", &b))
return 1;
if (!readDouble("Уведіть C = ", &c))
return 1;
if (!readDouble("Уведіть D = ", &d))
return 1;
printf("\nВихідні дані: A = %.6f B = %.6f C = %.6f D = %.6f\n", a, b, c, d);
/* Перевірка області визначення виразу. */
if (c <= 0.0) {
printf("Вираз не визначено: ln(C) існує лише при C > 0.\n");
return 2;
}
if (d == 0.0) {
printf("Вираз не визначено: ділення на нуль (D = 0).\n");
return 2;
}
const double cosB = cos(b);
const double radicand = a * cosB * cosB + 1.0;
if (radicand < 0.0) {
printf("Вираз не визначено: підкореневий вираз A*cos^2(B)+1 = %.6f < 0.\n",
radicand);
return 2;
}
const double x = sqrt(radicand) * log(c) / d;
/* Проміжні результати виводяться для перевірки достовірності обчислень. */
printf("\nПроміжні результати:\n");
printf(" cos(B) = %.10f\n", cosB);
printf(" cos^2(B) = %.10f\n", cosB * cosB);
printf(" A*cos^2(B) + 1 = %.10f\n", radicand);
printf(" sqrt(...) = %.10f\n", sqrt(radicand));
printf(" ln(C) = %.10f\n", log(c));
printf("\nРезультат: X = %.10f\n", x);
return 0;
}
Завдання 2 — task2.cpp
/*==============================================================================
Лабораторна робота №1. Завдання 2. Варіант 19.
Тема: типи даних, функції введення-виведення, обчислення виразів.
Умова: нехай число ab містить цифри a і b. Довести, що число ab + ba
ділиться на 11.
Аналіз задачі (аналітичне обґрунтування).
Двоцифрове число ab у позиційній десятковій системі має значення
ab = 10*a + b,
а число, записане тими самими цифрами у зворотному порядку,
ba = 10*b + a.
Тоді
ab + ba = (10a + b) + (10b + a) = 11a + 11b = 11*(a + b).
Отже сума є добутком числа 11 на ціле число (a + b), тобто ділиться
на 11 без остачі, причому частка дорівнює сумі цифр. Що й треба було
довести.
Метод програмної перевірки: програма
1) обчислює ab + ba для введеного користувачем числа і показує
покроково всі складові тотожності;
2) виконує вичерпну перевірку тотожності для ВСІХ двоцифрових чисел
(a = 1..9, b = 0..9) — обчислювальне підтвердження доведення.
Введення-виведення: об'єкти класів потоків std::cin / std::cout
(форматне введення-виведення scanf/printf застосовано в завданні 1).
Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11.
Компілятор: g++ -std=c++17
==============================================================================*/
#include <iostream>
/*------------------------------------------------------------------------------
reverseTwoDigit — побудувати число з переставленими цифрами.
Параметри:
n [вхідний] — двоцифрове число ab (10..99).
Повертає: число ba = 10*b + a.
Локальні змінні:
a — цифра десятків числа n;
b — цифра одиниць числа n.
------------------------------------------------------------------------------*/
int reverseTwoDigit(int n)
{
const int a = n / 10;
const int b = n % 10;
return 10 * b + a;
}
/*------------------------------------------------------------------------------
proveForAll — вичерпна перевірка тотожності ab + ba = 11*(a+b) для всіх
двоцифрових чисел.
Параметри: немає.
Повертає: true — тотожність виконується для всіх 90 двоцифрових чисел;
false — знайдено контрприклад (теоретично неможливо).
Локальні змінні:
a, b — цифри числа;
ab, ba — саме число та число з переставленими цифрами;
sum — їх сума;
checked — кількість перевірених випадків.
------------------------------------------------------------------------------*/
bool proveForAll()
{
int checked = 0;
for (int a = 1; a <= 9; ++a) {
for (int b = 0; b <= 9; ++b) {
const int ab = 10 * a + b;
const int ba = 10 * b + a;
const int sum = ab + ba;
if (sum % 11 != 0 || sum / 11 != a + b)
return false; /* контрприклад */
++checked;
}
}
std::cout << "Перевірено випадків: " << checked
<< " — тотожність виконується для всіх двоцифрових чисел.\n";
return true;
}
/*------------------------------------------------------------------------------
readTwoDigit — прочитати двоцифрове число з контролем коректності введення.
Якщо введено не число або число поза межами 10..99, прапорець помилки
потоку знімається, залишок рядка відкидається і запит повторюється.
Параметри: n [вихідний] — адреса змінної для введеного числа.
Повертає : true — число прочитано; false — вхідні дані вичерпано.
------------------------------------------------------------------------------*/
bool readTwoDigit(int *n)
{
std::cout << "Уведіть двоцифрове число ab (10..99): ";
while (!(std::cin >> *n) || *n < 10 || *n > 99) {
if (std::cin.eof())
return false;
std::cin.clear(); /* зняти прапорець помилки */
std::cin.ignore(1024, '\n'); /* очистити буфер клавіатури */
std::cout << "Помилка: потрібне ціле число від 10 до 99. Повторіть: ";
}
return true;
}
/*------------------------------------------------------------------------------
Головна функція. Читає двоцифрове число, демонструє тотожність на ньому
та виконує вичерпну перевірку.
Локальні змінні:
n — введене двоцифрове число ab;
a, b — його цифри;
ba — число з переставленими цифрами;
sum — сума ab + ba.
------------------------------------------------------------------------------*/
int main()
{
std::cout << "Лабораторна робота №1, завдання 2 (варіант 19)\n"
"Виконав: студент групи ІПЗ-11 Одарчук Олексій\n"
"Доведення: ab + ba ділиться на 11\n"
<< std::endl;
int n = 0;
if (!readTwoDigit(&n)) {
std::cout << "\nВхідні дані вичерпано." << std::endl;
return 1;
}
const int a = n / 10;
const int b = n % 10;
const int ba = reverseTwoDigit(n);
const int sum = n + ba;
std::cout << "\nЦифри числа: a = " << a << ", b = " << b << std::endl;
std::cout << " ab = 10*a + b = 10*" << a << " + " << b << " = " << n << std::endl;
std::cout << " ba = 10*b + a = 10*" << b << " + " << a << " = " << ba << std::endl;
std::cout << " ab + ba = " << n << " + " << ba << " = " << sum << std::endl;
std::cout << " 11*(a + b) = 11*(" << a << " + " << b << ") = " << 11 * (a + b)
<< std::endl;
std::cout << " " << sum << " / 11 = " << sum / 11 << ", остача = " << sum % 11
<< std::endl;
if (sum % 11 == 0)
std::cout << "\nСума ділиться на 11 без остачі." << std::endl;
else
std::cout << "\nСума НЕ ділиться на 11." << std::endl;
std::cout << "\nВичерпна перевірка тотожності ab + ba = 11*(a + b):" << std::endl;
if (!proveForAll())
std::cout << "Знайдено контрприклад — тотожність хибна." << std::endl;
return 0;
}
6. Результати виконання роботи
Компіляція: make (gcc -std=c17 та g++ -std=c++17,
прапорці -Wall -Wextra -pedantic -O2). Попереджень компілятора немає.
Нижче наведено екранні копії повних прогонів програм: кожна починається з запуску програми, містить усе введення з клавіатури й увесь вивід до завершення роботи. Прогін, що не вміщується на один екран, подано кількома послідовними частинами. Протоколи всіх прогонів, зокрема додаткових наборів вхідних даних, винесено окремими файлами за посиланнями.
Повний протокол виконання (task1.txt) — повний протокол, 81 рядків
Повний протокол виконання (task2.txt) — повний протокол, 77 рядків
7. Аналіз достовірності результатів
Достовірність результатів перевірено аналітичним розрахунком і обчисленнями на калькуляторі. Для кожної контрольної величини поруч із розрахунком наведено результат програми.
Перевірка розрахунків на калькуляторі
Нижче наведено екранні копії обчислень у калькуляторі Wolfram|Alpha; поруч із кожною — результат програми.
Калькулятор: 1,5230168822…; програма: 1,5230168822. Значення збігаються.
Калькулятор: 121; програма: 121, і 11·(4+7) = 121. Значення збігаються.
Завдання 1
Достовірність перевірено на контрольних наборах, значення яких обчислюються аналітично.
| Набір даних | Аналітичний розрахунок | Результат програми |
|---|---|---|
| A=3, B=π/3, C=10, D=2 |
cos(π/3)=0,5; 3·0,25+1=1,75; √1,75=1,32287566; ln10=2,30258509; X = 1,32287566·2,30258509/2 = 1,52301688 |
1,5230168822 — збіг до всіх виведених цифр |
| A=0, B=0, C=e, D=1 | √(0+1)·ln(e)/1 = 1·1/1 = 1,0000000 | 1,0000000000 — збіг точний |
| A=1, B=0, C=−5, D=2 | ln(−5) не існує | Повідомлення «Вираз не визначено: ln(C) існує лише при C > 0» |
Аргумент B вводиться з клавіатури як десяткове наближення π/3 ≈ 1,0471975512. Відхилення від точного π/3 (близько 3·10⁻¹¹) змінює результат лише в дванадцятому знаку після коми, тому результат програми 1,5230168822 збігається з аналітичним значенням для точного π/3 до всіх виведених цифр.
Завдання 2
| n | ab + ba | 11·(a+b) | Остача від ділення на 11 |
|---|---|---|---|
| 47 | 47 + 74 = 121 | 11·11 = 121 | 0 |
| 10 | 10 + 1 = 11 | 11·1 = 11 | 0 |
| 99 | 99 + 99 = 198 | 11·18 = 198 | 0 |
Обчислені значення збігаються з ручним розрахунком. Вичерпний перебір усіх 90 двоцифрових чисел контрприкладів не виявив, що узгоджується з аналітичним доведенням.
8. Висновки
-
Вивчено вбудовані типи даних та застосовано тип
doubleдля обчислень з дійсними числами. -
Опрацьовано два способи введення-виведення: форматні функції
scanf()/printf()(завдання 1) та об'єкти потоківstd::cin/std::cout(завдання 2). -
Застосовано стандартні математичні функції
cos(),sqrt(),log(). - Реалізовано контроль коректності введення: при введенні нечислових даних буфер клавіатури очищується і запит повторюється, що унеможливлює зациклення програми.
- Перед обчисленням перевіряється область визначення виразу, тому програма не виконує ділення на нуль і не обчислює логарифм від'ємного числа.
-
Тотожність
ab + ba = 11·(a + b)доведено аналітично та підтверджено вичерпним перебором. - Обидва завдання варіанта виконано в повному обсязі.