W poprzednim wpisie, zatytułowanym Wyrażenia algebraiczne (już kiedyś o tym słyszałem…) poznaliśmy podstawowe zasady dotyczące, jak sama nazwa mówi wyrażeń algebraicznych w C#. Dziś opowiemy sobie również o wyrażeniach, jednak będą to wyrażenia logiczne.
1. Wyrażenia logiczne – Operatory logiczne
Zarówno w świecie rzeczywistym jak i w językach programowania istnieje wiele zjawisk oraz obiektów, które można opisać zerojedynkowo (prawda lub fałsz).
W językach programowania jednak przewidziano specjalny typ danych do opisywania danych logicznych – w języku C# tym typem jest bool (z ang. boolean – boolowski, zerojedynkowy).
Jakie zatem wartości przyjmuje ten typ? Nie trudno się domyślić – są nimi true lub false.
Idąc tym tropem, śmiało zatem możemy powiedzieć, że wyrażenie logiczne, to takie wyrażenie, którego wartość jest typu bool, wartość taką możemy przypisać do zmienne typu bool lub bezpośrednio wykorzystać w instrukcji sterującej.
Argumenty wyrażenia logicznego musza być typu logicznego bool, ale nie muszą to być wyłącznie zmienne lub stałe tego typu – argumentami mogą również być wyrażenia relacyjne oraz wywołane metody, które zwracają wartość typu bool.
O tym czym są metody, powiem w kolejnych wpisach, dziś zajmiemy się jedynie wyrażeniami relacyjnymi.
W poprzednim wpisie używaliśmy operatorów przypisania, dziś skupimy się na operatorach relacji oraz operatorach logicznych.
Operatory relacji:
== równe (y == x)
!= różne ( y != x)
< mniejsze (y < x)
<= mniejsze, równe ( y <= x)
> większe ( y > x)
>= większe, równe (y >= x)
Operatory logiczne:
! negacja (bool y = false), bool x = !=y // x będzie równe true)
&& koniunkcja warunkowa (int x = 0, y = 1; bool z; z= x >5 && y++ >10 // z przyjmie false, a y nie ulegnie zmianie (do sprawdzenia tej części warunku nie dojdzie czyli nadal będzie równe 1))
& koniunkcja (int x = 0, y = 1; bool z; z = x > 5 & y++ > 10 // z przyjmie false, y będzie równe 0)
I I alternatywa warunkowa (int x = 10, y = 1; bool z; z = x > 5 II y ++ > 10 // z przyjmie true, y nie ulegnie zmianie (do sprawdzenia tej części warunku nie dojdzie, czyli nadal będzie równe 1))
I alternatywa (int x = 10, y = 1; bool z; z = x > 5 I y++ > 10 // z przyjmie true a y będzie równe 2)
Powiedzmy sobie nieco więcej nt. operatorów koniunkcji. Zanim to jednak zrobimy przypomnijmy sobie podstawowe operacje logiczne wg. algebry Boole’a – poniższa tabelka powinna być nam doskonale znana ze szkoły, nie mniej jednak w gwoli przypomnienia…:
Przykład 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { double wiek = 19, kwota = 25; bool kino; kino = (wiek >= 18 && kwota > -20); Console.WriteLine(kino); Console.ReadKey(); } } } |
Powyższy przykład prezentuje działanie operatora koniunkcji warunkowej, gdzie zadeklarowane mamy dwie zmienne typu double (wiek, kwota) oraz jedną zmienną typu bool (kino).
Do zmiennej typu bool przypisana jest wartość logiczna, która będzie wynikiem operacji logicznej (koniunkcji warunkowej) dla wyrażeń relacyjnych.
Wynikiem zapisu powyższego wyrażenia wartość która spełnia warunki (osoba minimum 18-letnia, posiadająca minimum 20,00 powiedzmy PLN-ów).
Przykład ten rzecz jasna zwróci nam po uruchomieniu wartość true ponieważ na początku zadeklarowaliśmy wartość dla zmiennych x i y, które jak widzimy mają wartość przypisaną równą kolejno 19 i 25.
Jeśli zmienimy wartość przypisania choćby dla jednej ze zmiennych na wartość nie spełniającą niżej zapisanego warunku otrzymamy wartość false – zgodnie z zasadą koniunkcji algebry wg. Boole’a.
Przykład 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { double wiek = 19, kwota = 20; bool kino; kino = (wiek >= 18 && kwota++ >= 20); Console.WriteLine(kino); Console.WriteLine(kwota); Console.ReadKey(); } } } |
Przykład 2 prezentuje bardzo podobny zapis, jednak poza wykorzystaniem koniunkcji warunkowej wykorzystuje poznany we wcześniejszym wpisie operator inkrementacji (++). Ponadto w konsoli zostanie również po wykonaniu tego kody wyświetlona wartość dla zmiennej kwota w celu pokazania działania zastosowanego operatora inkrementacji.
Zapisany kod w swoim wyniku powinien po uruchomieniu wyświetlić wartość true oraz 21.
A co gdy w powyższym przykładzie zmienimy przypisaną wartość dla którejś zmiennej, która nie będzie spełniać warunku zapisanego naszym wyrażeniu algebraicznym, np. wiek = 16?
Otóż po uruchomieniu programu otrzymamy niewłaściwy wynik… Właściwie otrzymamy false, jednak nasz zapis inkrementacji dotyczący kwoty nie zwiększy nam jej do 21. Czemu? Za sprawą operatora koniunkcji warunkowej, który sprawi, że ze względu na niespełnienie pierwszego z warunków zapisu, drugi zostanie niezbadany przez kompilator.
Rozwiązaniem tego błędy jest zastosowanie operatora koniunkcji (bezwarunkowej) czyli &.
2. Wyrażenia logiczne – Operatory alternatywy
Podobnie do koniunkcji, w języku C# mamy do dyspozycji dwa operatory alternatywy, a mianowicie alternatywa warunkowa oraz alternatywa (bezwarunkowa).
W przypadku alternatywy zdań, wynik wyrażenia logicznego jest prawdziwy jeśli choć jedno ze zdań składowych jest prawdziwe (Przykład 4). W przypadku zaś użycia alternatywy warunkowej zaniechane jest sprawdzanie drugiego argumentu wyrażenia logicznego jeśli pierwszy jest prawdziwy (Przykład 3).
Przykład 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { int x = 3; bool wynik; wynik = (x >= 2 || x++ >= 4); Console.WriteLine(wynik); Console.WriteLine(x); Console.ReadKey(); } } } |
Przykład 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { int x = 3; bool wynik; wynik = (x >= 2 | x++ >= 4); Console.WriteLine(wynik); Console.WriteLine(x); Console.ReadKey(); } } } |
Będąc przy operatorach logicznych warto też wspomnieć o tym, iż operator koniunkcji oraz operator alternatywy wykorzystywane są w operacjach bitowych o których więcej może kiedyś w innej serii.
3. Wyrażenia logiczne – Złożone wyrażenia logiczne
Bardziej niż pewne jest to, że w naszej przyszłości programistycznej spotkamy się z bardziej złożonymi wyrażeniami logicznymi niż te omawiane wyżej, służące jedynie jako przykład zastosowania pewnych operatorów.
Mogą one bowiem zawierać operator negacji (!), który jest operatorem jednoargumentowym.
Poniżej przykład takiego bardziej złożonego wyrażenia logicznego.
Przykład 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { int x = 1, y = 2; bool wynik; wynik = ((x == 1 || x == 3 || x == 5) && y < 1); Console.WriteLine(wynik); Console.ReadKey(); } } } |
Podobnie jak w matematyce tak i również w programowaniu, operatory arytmetyczne i logiczne podporządkowane są pewnym regułom.
Regułom taką jest m.in. priorytetowość operatorów logicznych co przedstawia po części poniższa tabela.
Tabela zawiera tylko wybrane operatory. Pełny wykaz operatorów znajduje się w dokumentacji MSDN pod tym linkiem.
Operator im wyżej w tabeli, tym większy jest jego priorytet.
Co zatem z operatorem negacji, który jest niema na samym szczycie naszych priorytetowych operatorów logicznych?
W przykładzie 6 i 7 pokażemy, że kompilator uwzględnia go z najwyższym priorytetem dla zapisanego wyrażenia logicznego; zarówno jeśli użyjemy go tuż przed zapisem wyrażenia jak i tuż przed zadeklarowaną zmienną logiczną.
Przykład 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { int x = 1, y = 2; bool wynik; wynik = !((x == 1 || x == 3 || x == 5) && y < 1); //zapis negacji przed wyrażeniem logicznym Console.WriteLine(wynik); Console.ReadKey(); } } } |
Przykład 7
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wyrazenia_logiczne { class Program { static void Main(string[] args) { int x = 1, y = 2; bool wynik; wynik = ((x == 1 || x == 3 || x == 5) && y < 1); Console.WriteLine(!wynik); //zapis negacji przed zadeklarowaną zmienną logiczną Console.ReadKey(); } } } |
Tak jak wspominałem wyżej poziom złożoności wyrażeń logicznych może być o wiele większy niż w przypadku tego prezentowanego ww. przykładach, niemniej jednak we wszystkich obowiązują te same zasady, m.in. priorytety operatorów, łączności; które to za pewnością zostaną bardziej szczegółowo omówione w kolejnych wpisach tej serii.
Dziś wstępnie omówiliśmy sobie wyrażenia logiczne, kolejny wpis z tej serii poświęcony zaś będzie operacjom na tekstach.
Stay tuned! 🙂