Лого на 91. НЕГ „Проф. Константин Гълъбов“

Модул 1 · Урок 9

Сравнения и логически операции

Типът bool, шестте операции за сравняване и трите логически операции. Булева алгебра, законите на Де Морган и частичното оценяване на логически изрази.

Защо ни е това

Досега процесите ни бяха линейни. За да може програмата да взема решение — дали да продължи по реда, или да направи преход другаде — тя трябва да провери някакво условие. Този урок е за условията: как се записват и как се комбинират.

Ключово

Всяка проверка завършва с една от две стойности: 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):

xyx && yx || y
0000
0101
1001
1111
x!x
01
10

Бележка

Приоритет. Най-висок е приоритетът на отрицанието; конюнкцията е с по-висок приоритет от дизюнкцията. Асоциативността е лява. Приоритетът на логическите операции е по-нисък от този на сравняванията — затова 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):

aba && b!(a && b)!a!b!a || !b
0001111
0101101
1001011
1110000

Във всички редове стойностите на колони 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.
  • Приоритет: първо сравненията, после !, после &&, накрая ||.
  • Законите на Де Морган: отрицанието „влиза“ в скобите и обръща && в || и обратно.
  • При частично оценяване вторият операнд може изобщо да не се пресметне — това позволява да се предпазиш от деление на нула.