На цьому уроці ми розглянемо логічні оператори І, АБО та НЕ в мові С++.
Логічні оператори
У той час як оператори порівняння використовуються для перевірки конкретної умови: помилкова вона чи істинна, вони можуть перевірити тільки одну умову за певний проміжок часу. Але бувають ситуації, коли потрібно протестувати відразу декілька умов. Наприклад, щоб дізнатися, чи виграли ми в лотерею, нам потрібно порівняти всі цифри купленого квитка з виграшними. Якщо в лотереї 6 цифр, то потрібно виконати 6 порівнянь, всі з яких мають бути true.
Також іноді нам потрібно знати, чи є хоч одне з декількох умов істинним. Наприклад, ми не підемо сьогодні на роботу, якщо хворі або дуже втомилися, або якщо виграли в лотерею 🙂 Нам потрібно перевірити, чи є хоч одна з цих 3-х умов істинною. Як це зробити? За допомогою логічних операторів! Вони дозволяють перевірити відразу декілька умов за один раз.
У мові C++ є 3 логічних оператори:
| Оператор | Символ | Приклад | Операція |
| Логічне НЕ | ! | !x | true, якщо x — false і false, якщо x — true |
| Логічне І | && | x && y | true, якщо x і y — true, в протилежному випадку — false |
| Логічне АБО | || | x || y | true, якщо x чи y — true, в протилежному випадку — false |
Логічний оператор НЕ
Ми вже з ним стикалися на уроці про логічний тип даних bool.
| Логічний оператор НЕ (!) | |
| Операнд | Результат |
| true | false |
| false | true |
Якщо операндом є true, то після застосування логічного НЕ результатом стане false. Якщо ж операнд до застосування оператора НЕ є false, то після його застосування стане true. Іншими словами, логічний оператор НЕ змінює результат з true на false і навпаки. Він часто використовується в умовних виразах:
|
1 2 3 4 5 |
bool bTooLarge = (x > 100); // змінна bTooLarge буде true, якщо x > 100 if (!bTooLarge) // Робимо що-небудь з x else // Виводимо помилку |
Слід пам’ятати, що логічний оператор НЕ має дуже високий рівень пріоритету. Початківці часто роблять наступну помилку:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int x = 5; int y = 7; if (!x == y) std::cout << "x does not equal y"; else std::cout << "x equals y"; return 0; } |
Результат виконання програми:
х equals у
Але х не дорівнює у, як це можливо? Оскільки пріоритет логічного оператора НЕ вище, ніж пріоритет оператора рівності, то вираз !х==у обчислюється як (!х)==у. Так як х — це 5, то !x — це 0. Умова 0==у помилкова, тому виконується частина else!
Нагадування: Будь-яке ненульове ціле значення в логічному контексті є true. Оскільки х = 5, то х обчислюється як true, а ось !x = false, тобто 0. Використання цілих чисел в логічних операціях подібним чином може заплутати не тільки користувача, але і самого розробника, тому так робити не рекомендується!
Правильний спосіб написання вищенаведеної програми:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int x = 5; int y = 7; if (!(x == y)) std::cout << "x does not equal y"; else std::cout << "x equals y"; return 0; } |
Спочатку обчислюється х==у, а потім вже оператор НЕ змінює результат на протилежний.
Правило: Якщо логічний оператор НЕ повинен працювати з результатами роботи інших операторів, то інші оператори і їх операнди повинні знаходитися в круглих дужках.
Логічний оператор АБО
Якщо хоч одне з двох умов є істинним, то логічний оператор АБО є true.
| Логічний оператор АБО (||) | ||
| Лівий операнд | Правий операнд | Результат |
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | true |
Розглянемо наступну програму:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int main() { std::cout << "Enter a number: "; int value; std::cin >> value; if (value== 0 || value== 1) std::cout << "You picked 0 or 1" << std::endl; else std::cout << "You did not pick 0 or 1" << std::endl; return 0; } |
Тут ми використали логічний оператор АБО, щоб перевірити, чи є хоч одна з двох умов істинною: ліва (value==0) або права (value==1). Якщо хоч одна з умов є true або обидві відразу є true, то виконуватися буде стейтмент if. Якщо жодна з умов не є true, то результат — false і виконуватися буде стейтмент else.
Ви можете поєднувати відразу декілька умов:
|
1 2 |
if (value == 0 || value == 1 || value == 2 || value == 3) std::cout << "You picked 0, 1, 2, or 3" << std::endl; |
Початківці іноді плутають логічне АБО (||) з побітовим АБО (|). Хоча у них і однакові назви, функціонал у них різний.
Логічний оператор І
Тільки за умови, що обидва операнди будуть істинними, логічний оператор І буде true. Якщо ні, то тоді false.
| Логічний оператор І (&&) | ||
| Лівий операнд | Правий операнд | Результат |
| false | false | false |
| false | true | false |
| true | false | false |
| true | true | true |
Наприклад, ми хочемо знати, чи знаходиться значення змінної х в діапазоні від 10 до 20. Тут у нас є дві умови: ми повинні перевірити, чи є х більше 10 і чи є х менше 20.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int main() { std::cout << "Enter a number: "; int value; std::cin >> value ; if (value > 10 && value < 20) std::cout << "Your value is between 10 and 20" << std::endl; else std::cout << "Your value is not between 10 and 20" << std::endl; return 0; } |
Якщо обидві умови істинні, то виконується частина if. Якщо ж хоча б одна або відразу обидві умови помилкові, то виконується частина else.
Як і з логічним АБО, ми можемо комбінувати відразу декілька умов І:
|
1 2 3 4 |
if (value > 10 && value < 20 && value != 16) // Робимо що-небудь else // Робимо що-небудь інше |
Короткий цикл обчислення
Для того, щоб логічне І повертало true, обидва операнди повинні бути істинними. Якщо перший операнд обчислюється як false, то оператор І повинен відразу повертати false незалежно від результату другого операнду (навіть без його обробки). Це називається коротким циклом обчислення і виконується він, в першу чергу, в цілях оптимізації.
Аналогічно, якщо перший операнд логічного АБО є true, то і вся умова буде true (навіть без обробки другого операнду).
Як і у випадку з оператором АБО, початківці іноді плутають логічне І (&&) з побітовим І (&).
Використання операторів І/АБО
Іноді виникають ситуації, коли змішування логічних операторів І та АБО в одному виразі не уникнути. Тоді слід знати про можливі проблеми, які можуть статися.
Багато програмістів вважають, що логічні І та АБО мають однаковий пріоритет (або забувають, що це не так), так само як і додавання/віднімання або множення/ділення. Проте пріоритет логічного І вище пріоритету АБО. Таким чином, операції з оператором І завжди обчислюватимуться першими (якщо тільки операції з АБО не перебувають в круглих дужках).
Розглянемо наступний вираз: value1 || value2 && value3. Оскільки пріоритет логічного І вище, то і обчислюватися вираз буде так:
value1 || (value2 && value3)
а не так
(value1 || value2) && value3
Хорошою практикою є використання круглих дужок з операціями. Це запобіжить помилкам пріоритету, збільшить читабельність коду і чітко дасть зрозуміти компілятору, як слід обчислювати вирази. Наприклад, замість того, щоб писати value1 && value2 || value3 && value4, краще записати (value1 && value2) || (value3 && value4).
Правила де Моргана
Багато програмістів роблять помилку, думаючи, що !(x && y) — це те ж саме, що і !x && !y. На жаль, ви не можете “використовувати” логічне НЕ подібним чином.
Правила де Моргана говорять, що:
!(x && y) еквівалентно !x || !y
!(x || y) еквівалентно !x && !y
Іншими словами, логічні оператори І та АБО міняються місцями! У деяких випадках це навіть корисно, оскільки покращує читабельність.
А де ж побітове виключне АБО (XOR)?
Побітове виключне АБО (XOR) — це логічний оператор, який використовується в деяких мовах програмування для перевірки на істинність непарної кількості умов.
| Побітове виключне АБО (XOR) | ||
| Лівий операнд | Правий операнд | Результат |
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | false |
У мові C++ такого оператора немає. На відміну від логічних І/АБО, до XOR не застосовується короткий цикл обчислення. Однак його легко можна зімітувати, використовуючи оператор нерівності (!=):
|
1 |
if (a != b) ... // a XOR b (припускається, що a і b - типу bool) |
Можна також збільшити кількість операндів:
|
1 |
if (a != b != c != d) ... // a XOR b XOR c XOR d (припускається, що a, b, c і d - типу bool) |
Слід зазначити, що вищенаведені шаблони XOR працюють тільки, якщо операнди є логічного типу даних (а не цілочисельних типів). Якщо ви хочете, щоб це працювало і з цілими числами, то використовуйте оператор static_cast.
Форма XOR, яка працює і з іншими типами даних (за допомогою оператора static_cast ми можемо конвертувати будь-який тип даних в bool):
|
1 |
if (static_cast<bool>(a) != static_cast<bool>(b) != static_cast<bool>(c) != static_cast<bool>(d)) ... // a XOR b XOR c XOR d, для будь-якого типу, який може бути конвертований в bool |
Тест
Який результат виконання наступних виразів?
Вираз №1: (true && true) || false
Вираз №2: (false && true) || true
Вираз №3: (false && true) || false || true
Вираз №4: (5 > 6 || 4 > 3) && (7 > 8)
Вираз №5: !(7 > 6 || 3 > 4)
Відповідь
Примітка: У відповідях пояснення виконується за допомогою стрілочки (=>). Наприклад, (true || false) => true означає, що результатом виразу (true || false) є true.
Вираз №1: (true && true) || false => true || false => true
Вираз №2: (false && true) || true => false || true => true
Вираз №3: (false && true) || false || true => false || false || true => false || true => true
Вираз №4: (5 > 6 || 4 > 3) && (7 > 8) => (false || true) && false => true && false => false
Вираз №5: !(7 > 6 || 3 > 4) => !(true || false) => !true => false

(92 оцінок, середня: 4,89 з 5)