C++ programozás 7. – Logikai műveletek, logikai kifejezések

Logikai műveletek, logikai kifejezések, avagy a feltételvizsgálatok alapjai

Logikai kifejezésnek nevezzük azt, amelynek az eredménye igaz vagy hamis (true – false) lehet. Ezek valójában eldöntendő kérdések:

  • a szám páros?
  • a szám osztható 3-mal?
  • a szám kisebb, mint 100?

A logikai kifejezések előfutáraként az operátorokat bemutató leckében szót ejtettem a különféle logikai operátorokről:

  • Negálás: Egy logikai értéket az ellenkezőjére állít (ami true volt, false lesz, és fordítva)
  • Logikai és: Akkor igaz az összetett kifejezés, ha minden részfeltétele igaz (ha bármelyik hamis, hamis az egész)
  • Logikai vagy: Akkor hamis az összetett kifejezés, ha minden részfeltétele hamis (ha bármelyik igaz, igaz az egész)
  • Kizáró vagy: Akkor igaz összetett kifejezés, ha a részfeltételek közül csak egy igaz (ha több részfeltétel igaz, vagy mind hamis, akkor hamis az egész)

Jöjjön akkor pár kapcsolódó példa:

Adj meg olyan logikai kifejezést, mely igaz értéket ad pozitív páros számok esetén:

szám % 2 == 0 && szám > 0

Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám nagyobb, mint 10 és páratlan:

szám > 10 && szám % 2 != 0

Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám a 10 és 30 között van:

szám > 10 && szám < 30

Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám osztható 3-mal vagy 7-tel:

szám % 3 == 0 || szám % 7 == 0 

Adj meg olyan logikai kifejezést, mely igaz értéket ad, ha a szám nem negatív vagy páros:

!(szám < 0) || szám % 2 == 0

Az előző másképp:

szám >= 0 || szám % 2 == 0

Adj meg olyan logikai kifejezést, mely a négyes vagy ötös dolgozatjegyre ad igaz értéket:

jegy == 4 ^ jegy == 5

Rövidzár kiértékelés

A logikai kifejezésekkel kapcsolatban fontos megemlíteni az úgynevezett rövidzár kiértékelést. Ez a szabály a logikai és, valamint a logikai vagy esetén érvényes. A rövidzár kiértékelés picit másképp működik a két esetben, de teljesen logikus lesz, ha megérted.
Logikai és műveletnél emlékszel arra, hogy csak akkor igaz az összetett kifejezés, ha minden részfeltétele igaz. Ez azt jelenti, hogy ha akár csak egyetlen hamisat találunk, akkor a többit felesleges is megvizsgálni. Nézzünk rá egy példát. Ha egy olyan feltételt szeretnénk megadni, amely olyan számokat fogad el, melyek 3-mal és 4-gyel is oszthatók, akkor a következőt tesszük:

szám % 3 == 0 && szám % 4 == 0

Mit is csinál a C++ pontosan? A logikai és két oldalát a balról jobbra elv alapján vizsgálja meg. Ha a szám osztható 3-mal, akkor meg kell nézni a jobb oldali feltételt is, mert csak akkor igaz az egész, ha minden része igaz. És ha a bal oldal hamis? Akkor már nem is lehet soha igaz, és – ez a legfontosabb! – a jobb oldali feltételt már meg sem vizsgálja! Nagyon fontos ezzel tisztában lenni, mert sokszor használatos.

Ugyanez az elv létezik a logikai vagy esetén is, csak pont fordítva. Egy olyan feltételt szeretnénk megadni, amely olyan számokat fogad el, melyek 3-mal vagy 4-gyel is oszthatók (esetleg mindkettővel), akkor a következőt tesszük:

szám % 3 == 0 || szám % 4 == 0

Akkor egy kis deja vu. Mit is csinál a C++ pontosan? A logikai vagy két oldalát a balról jobbra elv alapján vizsgálja meg. Ha a szám nem osztható 3-mal, akkor meg kell nézni a jobb oldali feltételt is, mert csak akkor igaz az ha van benne legalább egy igaz. És ha a bal oldal igaz? Akkor már igaz az egész kifejezés, és a jobb oldali feltételt már meg sem vizsgálja! Olyan ez, mint amikor amikor a kitűnő vagy bukott diákokat vizsgáljuk. Akkor kitűnő, ha minden jegye 5-ös, és akkor bukott, ha van 1-es érdemjegye. Feltételekkel ez hogy nézne ki? Egy későbbi példa kedvéért legyen csak két tantárgya:

jegy1 == 5 && jegy2 == 5 

Ha már az első jegye nem 5-ös, akkor a többit meg se nézi a program, hiszen felesleges. Hasonlóan a bukott diák:

jegy1 == 1 || jegy2 == 1 

Ha már az első jegye 1-es, akkor a többit meg se nézi a program, mert már igaz az összetett feltétel, ha van 1-es jegye, akkor megbukott.

Negálás

A negálás olyan terület, ahol könnyen hibázhat az ember. Ugyanazt a vizsgálatot két oldalról is meg lehet közelíteni, és mindkettő helyes. Vegyük például a már emlegetett kitűnő tanulónkat. Azt, hogy valaki kitűnő úgy definiáljuk, hogy minden jegye 5-ös. Igen ám, de azt is mondhatom, hogy nincs olyan jegye, ami nem 5-ös. Elsőre meredek lehet, a dupla tagadás amúgy kedvenc a magyar nyelvben. Lássuk akkor példával:

jegy1 == 5 && jegy2 == 5 

Ez már ismerős volt, ő a kitűnő. Akkor nézzük meg így:

!(jegy1 != 5 || jegy2 != 5) 

Mit is írtam itt pontosan? A vagy miatt, ha legalább az egyik jegye nem 5-ös, akkor igaz a zárójeles kifejezés – ami azt jelenti, hogy nem kítűnő – majd ezt az egészet negálva hamisat kapok, mégiscsak kitűnő. Nincs olyan jegye, ami nem 5-ös. A vaggyal összekötött részfeltételek együtt csak akkor hamisak, ha mindegyik hamis, vagyis minden jegye NEM 5-ös. Ha minden jegye NEM 5-ös és ezt tagadom, az pedig azt jelenti, hogy minden jegye 5-ös, vagyis kitűnő. Nem egyszerű példa, ez az egész a matematikai logikában és halmazelméletben ismert De Morgan azonosságokra vezethető vissza. Ami a lényeg az egészből: ugyanarra kétféle megoldás is létezik, melyek teljes mértékben megegyeznek, neked csak az a feladatod, hogy a számodra egyszerűbbet megtaláld. Hasonlóan immár magyarázat nélkül megmutatom két példával a bukott diák esetét is:

jegy1 == 1 || jegy2 == 1
// vagy
!(jegy1 != 1 && jegy2 != 1 )

Na jó, egy kis magyarázat a második esethez. Ha egyik jegye sem 1-es, és ezt tagadom, az mit jelent? Nem azt, hogy minden jegye 1-es! Azt jelenti, hogy van legalább egyetlen olyan, ami 1-es!
Ha a kifejezésben csak ÉS vagy csak VAGY logikai kapcsolatot használsz, de egyszerre a kettőt nem, akkor általános formában ez az átalakítás a következőképp néz ki:

  1. a logikai kapcsolatot változtasd át a másikra (és-t vagy-ra meg vagy-ot és-re)
  2. a használt relációkat változtasd az ellenkezőjére (vigyázz, emlékezz a relációknál tanultakra!)
  3. negáld az egész kifejezést

Na, még egy pár példa erre az átalakításra:

Írj kifejezést, ami a 3-mal és 5-tel nem osztható számokra ad igaz értéket:

szám % 3 != 0 && szám % 5 != 0
// vagy
!(szám % 3 == 0 || szám % 5 == 0)

Írj kifejezést, ami csak a [10;30] intervallumba NEM tartozó számokat fogadja el:

szám < 10 || szám > 30
// vagy
!(szám >= 10 && szám <= 30)

Írj kifejezést, ami csak a negatív páratlan számokat fogadja el:

szám < 0 && szám % 2 != 0
// vagy
!(szám >= 0 || szám % 2 == 0)

Oké, mondhatnád, hogy itt bonyolítjuk a dolgot, hiszen a negálást, mint műveletet beletesszük egy kifejezésbe, ami egyénként nincs benne. És ha fordítva van?

!(szám % 5 != 0 || szám < 0) // ööö, ez mit csinál?

Egyszerűsítsük!

szám % 5 == 0 && szám >= 0 // 5-tel osztható nem negatív szám

Következő lecke: Blokkok

2 Replies to “C++ programozás 7. – Logikai műveletek, logikai kifejezések”

  1. Pingback: C++ programozás 6. – Operátorok

  2. Pingback: C++ programozás 8. – Feltételvizsgálatok

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük

*

Ez a weboldal az Akismet szolgáltatását használja a spam kiszűrésére. Tudjunk meg többet arról, hogyan dolgozzák fel a hozzászólásunk adatait..