Защо ни е това
Досега процесите ни бяха линейни. За да може програмата да взема решение — дали да продължи по реда, или да направи преход другаде — тя трябва да провери някакво условие. Този урок е за условията: как се записват и как се комбинират.
Ключово
Всяка проверка завършва с една от две стойности: true (истина) или false (неистина). Това е целият материал — останалото са подробности как да ги получим и комбинираме.
Типът bool
В компютърната архитектура няма специален машинен тип със стойности true и false — за представянето им се използват цели числа. false се представя с нула, а true — с число, различно от нула, най-често 1.
За удобство на програмиста и за да не се бъркат логическите стойности с числовите, в езиците се добавя специализиран тип. В C# той е bool. Декларира се както всички останали:
bool x, y = true, z = false;
Console.WriteLine(x + " " + y);Внимание
При извеждане началните букви на двете стойности са главни — конзолата показва True False. Написани по този начин в програмата обаче те ще бъдат отхвърлени от компилатора като несъответстващи на синтаксиса. В кода се пише true и false с малки букви.
С sizeof(bool) можеш да провериш в колко байта се съхраняват логическите стойности в C#.
Операции за сравняване
Освен като константи, логическите стойности се получават и от операциите за сравняване върху числа или други сравними стойности. Знаците на четири от тях се различават от използваните в математиката:
| Знак | Значение | В математиката |
|---|---|---|
== | Равно | = |
> | По-голямо | > |
< | По-малко | < |
>= | По-голямо или равно | ≥ |
<= | По-малко или равно | ≤ |
!= | Не равно | ≠ |
Внимание
Обичайният знак за равенство = в C# се използва за присвояване. Сравнението за равенство е ==. Това е най-честата грешка на начинаещите — внимавай много.
Двата аргумента могат да са произволни изрази, стойностите на които могат да се сравняват. Не може обаче да се сравняват числови стойности с нечислови. Резултатът е логическа стойност и може да се присвои на променлива от тип bool:
int a = 12, b = 6, c = 20;
bool flag;
flag = a > b; // 12 > 6 е вярно -> true
flag = (a + b) >= c; // 18 >= 20 не е вярно -> falseЛогически операции
Често се налага да се комбинират няколко условия. Например „числото е в интервала от 0 до 10“ значи едновременно да е по-голямо или равно на 0 и по-малко или равно на 10. Такива по-сложни условия се образуват с логическите операции. Операндите им са булеви стойности и резултатът е също булева стойност.
| Операция | Знак | Записва се | Резултатът е true, когато |
|---|---|---|---|
| Конюнкция („и“) | && | инфиксно, бинарна | и двата операнда са true |
| Дизюнкция („или“) | || | инфиксно, бинарна | поне един операнд е true (false е само когато и двата са false) |
| Отрицание („не е вярно, че“) | ! | префиксно, унарна | операндът е false |
Таблиците на истинност (1 значи true, 0 значи false):
| x | y | x && y | x || y |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 |
| x | !x |
|---|---|
| 0 | 1 |
| 1 | 0 |
Бележка
Приоритет. Най-висок е приоритетът на отрицанието; конюнкцията е с по-висок приоритет от дизюнкцията. Асоциативността е лява. Приоритетът на логическите операции е по-нисък от този на сравняванията — затова a >= 0 && a <= 10 работи и без скоби.
Логически изрази
Логически израз (условие)
Израз, в който участват булеви стойности (например резултати от сравняване) и логически операции. Има логическа стойност в зависимост от стойностите на участващите променливи.
int a;
bool b = (a >= 0) && (a <= 10);
bool c = !((a < 0) || (a > 10));
// Същото, записано по-просто с приоритета на операциите:
bool b2 = a >= 0 && a <= 10;
bool c2 = !(a < 0 || a > 10);След изпълнението на този фрагмент b и c имат една и съща стойност — в зависимост от това дали a е в интервала от 0 до 10.
Булева алгебра
Логическите стойности и операции образуват алгебрична структура, различна от алгебрата на числата с аритметичните операции. Тя носи името на своя създател, английския математик Джордж Бул — булева алгебра. Ето свойствата, които най-често помагат при изграждане на логически изрази:
| Свойство | Записва се |
|---|---|
| Комутативност | a && b = b && a, a || b = b || a |
| Асоциативност | (a && b) && c = a && (b && c) — значи може без скоби |
| Двойно отрицание | !(!x) = x |
| Свойства на константите | a && true = a, a && false = false, a || true = true, a || false = a |
| Закони на Де Морган | !(a && b) = !a || !b, !(a || b) = !a && !b |
Всяко от тези свойства само по себе си е логически израз и верността му може да се провери, като се пресметне стойността му за всички възможни стойности на променливите. Ако стойността е true винаги — свойството е в сила. Ако дори за една комбинация излезе false — не е.
Доказателство на първия закон на Де Морган
Двете булеви променливи дават 4 комбинации. Пресмятаме лявата страна (колона 4) и дясната (колона 6):
| a | b | a && b | !(a && b) | !a | !b | !a || !b |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 1 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 0 | 0 | 0 | 0 |
Във всички редове стойностите на колони 4 и 7 са равни — твърдението на закона е в сила.
Частично оценяване
В някои случаи стойността на логически израз може да се пресметне по-бързо, без да се извършват всички участващи операции.
- Нека
x = false. Тогава за изразаx && (y || z)не е необходимо да се пресмятаy || z: съгласно свойствата на константите каквато и да е стойността му, целият израз ще еfalse. - Нека
x = true. Тогава за изразаx || (y || z)не е необходимо да се пресмятаy || z— целият израз ще еtrue.
Съвет
Това не е само оптимизация. Подредбата на условията може да те спаси от грешка: в broy > 0 && suma / broy > 5 делението изобщо не се стига, ако broy е нула. Обърнеш ли двете условия — програмата гърми.
Задачи
Упражнения
Задача 1.Два интервала на числовата права са зададени с левия и десния си край — [a,b] и [c,d], a < b, c < d. Напиши конзолно приложение, което въвежда краищата от стандартния вход и извежда True, ако двата интервала имат обща точка, или False — ако нямат.
Решение: интервалите имат обща точка, когато b е между c и d или a е между c и d. Значи условието е c <= b && b <= d || c <= a && a <= d. Провери програмата при всевъзможни взаимни разположения на двата интервала.
Задача 2. Промени програмата така, че да извежда True, ако един от двата интервала се съдържа изцяло в другия.
Задача 3. Промени програмата от задача 2 така, че отговорът True да се дава само когато вложеният интервал няма общ край с интервала, в който е вложен.
Въпроси
1. Нека int a = 3, b = 2, c = 4;. Каква е стойността на изразите: а) a < b && 3 < 0; б) a < b || 3 < 0; в) !((a - b) > c)?
2. Запиши като логически изрази условията: а) x е по-голямо или равно на 1 и по-малко или равно на 5; б) x не е по-голямо или равно на 1 нито по-малко или равно на 5; в) x е по-голямо или равно на 1 и по-малко или равно на −5.
Какво трябва да запомниш
=присвоява,==сравнява. Смесиш ли ги, програмата прави нещо друго, не това, което мислиш.- Конюнкцията е true само когато и двата операнда са true; дизюнкцията е false само когато и двата са false.
- Приоритет: първо сравненията, после
!, после&&, накрая||. - Законите на Де Морган: отрицанието „влиза“ в скобите и обръща
&&в||и обратно. - При частично оценяване вторият операнд може изобщо да не се пресметне — това позволява да се предпазиш от деление на нула.