tus0.gif (69 bytes)
 

ELEKTRONINĖS KNYGOS

tus0.gif (69 bytes)

Gintautas GRIGAS
PROGRAMAVIMAS PASKALIU

3. LOGINIAI DUOMENYS IR JŲ VALDOMI VEIKSMAI

Logika yra programavimo pagrindas. Sąsaja tarp matematikos ir programavimo prasideda nuo matematinės logikos.

Loginiai duomenys valdo programoje užrašytų veiksmų atlikimo tvarką.

Sakiniai, kurių atlikimo tvarką reikia valdyti (pasirinkti vieną iš kelių sakinių, kartoti) jungiami į struktūrinius sakinius, dar vadinamus valdymo struktūromis. Šiame skyriuje pateiksime pilną valdymo struktūrų rinkinį, t.y., tokį, kurio pakanka, bet kurio sudėtingumo veiksmų atlikimo tvarkai išreikšti.

3.1. Loginiai duomenys

Loginiai duomenys turi tik dvi reikšmes, kurios Paskalio kalboje žymimos vardais true ir false. Tai reikšmės teiginio, apie kurį galima pasakyti, kad jis yra teisingas arba klaidingas. Jeigu teiginys teisingas, tai sakoma, kad jo loginė reikšmė yra true, jei klaidingas – false. Pavyzdžiui, teiginio „Dabar lyja“ reikšmė yra true, jeigu dabar iš tikrųjų lyja ir false – priešingu atveju. Teiginys „skaičius 24 yra lyginis“ yra visada teisingas, nes skaičius 24 iš tikrųjų lyginis. Taigi, šio teiginio reikšmė yra true.

Teiginius kartais patogu vadinti sąlygomis. Sakoma, kad sąlyga gali būti tenkinama (jos loginė reikšmė yra true) arba netenkinama (false). Sąlygos, išreikštos nelygybe 5>3, reikšmė yra visada true, nes skaičius 5 didesnis už skaičių 3. Sąlygos 5=3 reikšmė yra false, nes skaičiai 3 ir 5 nelygūs. O kokia bus sąlygos a>5 reikšmė, iš anksto pasakyti negalima, nes ji priklauso nuo kintamojo a reikšmės.

Loginiai duomenys gali būti loginių uždavinių pradiniai ir galutiniai duomenys. Tokius uždavinius tenka retai programuoti. Tačiau su loginiais duomenimis susiduriame kiekvienoje programoje, kai reikia valdyti atliekamų veiksmų eilės tvarką. Dėl to juos ir nagrinėjame šio skyriaus pradžioje.

Loginiai kintamieji, kaip ir kitų tipų kintamieji, žymimi vardais. Kad būtų galima juos atskirti nuo kitų tipų kintamųjų, aprašuose jie apibūdinami žodžiu boolean, pavyzdžiui,

var a, b, log: boolean;

Šiuo aprašu pasakoma, kad kintamieji, pažymėti vardais a, b ir log, yra loginiai.

Loginiams kintamiesiems galima priskirti tik logines (loginių reiškinių) reikšmes. Loginės reikšmės – tai loginės konstantos false ir true. Todėl prieskyros sakiniai

a := true;
b := false;
log := a

yra teisingi, nes kintamieji a, b ir log yra loginio tipo. Tuo tarpu sakiniai:

a := 15;
b := 54.12

yra neteisingi, nes loginio tipo kintamieji negali įgyti skaitinių reikšmių.

Su loginiais duomenimis atliekamos logines operacijas:

not  inversija (ne),
and konjunkcija (ir),
or    disjunkcija (arba).

Visos loginės operacijos Paskalyje žymimos baziniais žodžiais, kurie angliškai reiškia tą, ką rašėme skliaustuose (ne, ir, arba).

Panagrinėkime kiekvieną operaciją.

Inversija (not). Operando reikšmė paneigiama, t.y. jo loginė reikšmė pakeičiama priešinga:

not false = true,
not true = false.

Pavyzdžiui, vietoj

a <> b
galima rašyti
not(a = b)

arba vietoj
a <= b
galima rašyti
not(a > b).

Inversija yra vienvietė operacija, t.y., ji taikoma vienam operandui – vienai loginei reikšmei. Šiuo požiūriu ji panaši į minusą, kuriuo užrašyta vienvietė atimtis aritmetiniame reiškinyje:

-x
not a

Ir vienos, ir kitos operacijos ženklas rašomas prieš operandą. Minusas keičia skaičiaus ženklą priešingu, o inversija – loginę reikšmę priešinga.

Konjunkcijos (and) reikšmė yra lygi true tiktai tuo atveju, kai abiejų operandų reikšmės yra true. Visais kitais atvejais konjunkcijos reikšmę yra false:

false and false = false,
false and true = false,
true and false = false,
true and true = true.

Konjunkcijos rezultatus galima pavaizduoti lentele.

a

b

a and b

false

false

false

false

true

false

true

false

false

true

true

true

Disjunkcijos (or) reikšmė yra lygi true, jei bent vieno operando reikšmė yra true. Kitaip sakant, disjunkcijos reikšmė‚ yra true, jei pirmojo arba antrojo operando reikšmė yra true (dėl to disjunkcija kartais vadinama operacija arba):

false or false = false,
false or true = true,
true or false = true,
true or true = true.

Disjunkcijos rezultatus galima pavaizduoti lentele.

a

b

a or b

false

false

false

false

true

true

true

false

true

true

true

true

Loginiai reiškiniai, panašiai kaip ir aritmetiniai, gali būti ir sudėtingesni, pavyzdžiui,

a and b and c,
a or b or c.

Loginių operacijų atlikimo tvarką nurodo skliaustai. O jeigu skliaustų nėra, tai operacijos atliekamos šia prioritetų eile:

not
and
or

T.y., pirmiausiai atliekamas neigimas, po to – konjunkcija ir paskiausiai – disjunkcija.

Vienodo prioriteto operacijos atliekamos iš kairės į dešinę. Pavyzdžiui, reiškinio

a or b or c or d and d and f

reikšmė skaičiuojama taip, lyg būtų šitaip surašyti skliaustai:

((a or b) or c) or ((d and e) and f).

Loginę (loginio reiškinio) reikšmę galima rašyti (parodyti ekrane), priskirti loginio tipo kintamajam, panaudoti valdymo struktūrose (žr. tolesnius skyrelius).

Programoje loginės reikšmės dažniausiai atsiranda kaip skaičių (aritmetinių reiškinių) lyginimo rezultatas. Vartojamos 6 lyginimo operacijos, kurios Paskalio kalboje žymimos šitaip:

<   mažiau,
<= mažiau arba lygu,
=   lygu,
<> nelygu,
>   daugiau,
>= daugiau arba lygu.

Pateiksime lyginimo operacijų ir jų rezultatų pavyzdžių.

5 < 6            true
5 > 6            false
5 > 5            false
5 >= 5          true
5-1 < 5         true
a-b = (c-d)-r  reikšmė priklausys nuo kintamųjų reikšmių
5.31 < 5.32   true
5.31 < 5       true

Lyginimo operacijų, panašiai kaip ir aritmetinių, operandai gali būti skirtingo tipo skaičiai (aritmetiniai reiškiniai). Tokiu atveju sveikasis skaičius pakeičiamas realiuoju ir lyginami du realieji skaičiai.

Loginių operacijų operandai dažnai būna lyginimo operacijų rezultatai. Jei nėra skliaustų, Paskalyje lyginimo operacijos atliekamos paskiausiai. Todėl lyginimo reiškinius, kai su jais atliekamos loginės operacijos, reikia suskliausti. Pavyzdžiui, reiškinyje

(x > 5) and (x < 10)

skliaustai reikalingi. Jei jų nebūtų, tai apskaičiuojant reiškinį

x > 5 and x < 10

pagal Paskalyje priimtus operacijų prioritetus pirmiausiai reikėtų atlikti loginę operaciją

5 and x

O tai neatitinka mūsų užmanymo. Be to pirmasis konjunkcijos operandas yra neleistino tipo (todėl šią klaidą aptiktų kompiliatorius).

Kelias paprastesnes sąlygas loginėmis operacijomis galima sujungti į vieną sudėtingesnę. Pavyzdžiui, dviguba nelygybe a<x<b matematikoje nurodomi skaičiaus x reikšmės rėžiai. Programavime toks užrašas neleistinas. Mat išeitų, kad pirmosios lyginimo operacijos a<x rezultatas, kuris yra loginė reikšmė, vėliau lyginamas su skaičiumi b, o skaičiai ir loginės reikšmės yra nepalyginami duomenys. Dvigubą nelygybę programavime galima pakeisti dviejų viengubų nelygybių konjunkcija:

(a < x) and (x < b)

Sąlyga tenkinama, t.y., čia parašyto reiškinio reikšmė yra true, tik tuo atveju, jeigu tenkinamos abi sąlygos, sujungtos konjunkcijos operacija: ir pirmoji, ir antroji. Dėl to konjunkcija kartais vadinama operacija ir.

Lyginti galima ne tik aritmetinius reiškinius (skaičius), bet ir visų kitų paprastųjų tipų duomenis (apie juos kalbėsime vėliau), tarp jų – ir loginius duomenis. Laikoma, kad reikšmė false yra mažesnė už true, t.y. tenkinama sąlyga false < true.

Pateiksime programų ar jų fragmentų pavyzdžių.

1 pavyzdys. Miestus A ir B jungia keliai, pažymėti linijomis (14 pav.). Keliai eina per penkis tiltus, pažymėtus loginiais kintamaisiais a, b, c, d ir e. Jeigu tiltu galima važiuoti, tai jį žyminčio kintamojo reikšmė yra true, jeigu ne (pavyzdžiui, tiltas remontuojamas), tai false.


14 pav. Tiltai

Loginiam kintamajam kelias priskiriama reikšmė true jeigu miestus A ir B jungia bent vienas kelias, einantis per veikiančius tiltus:

kelias := ((a or b) and d) or c and e

2 pavyzdys. Programa, nustatanti, ar metai olimpiniai.

Pirmosios vasaros olimpinės žaidynės įvyko 1896 m. Atėnuose. Po to jos vyko arba turėjo vykti kas ketveri metai: 1900 m. – antrosios, 1904 m. – 3-iosios ir t.t. Neįvykusioms žaidynėms taip pat buvo skiriamas eilės numeris, o jų metai vis tiek laikomi olimpiniais.

Pradinis duomuo – skaičius, reiškiantis metus. Rezultatas – loginė reikšmė true, jeigu metai olimpiniai, arba false, jeigu metai neolimpiniai.

program olimpiada;
  var metai: integer;
        olimp: boolean;               { ar metai olimpiniai }
begin
  read(metai);
  olimp := (metai >= 1896) and (metai mod 4 = 0);
  writeln(olimp)
end.

Jeigu kompiuteriui pateiksime pradinį duomenį 1999, tai jis ekrane parodys rezultatą

FALSE

nes 1999-ieji metai neolimpiniai.

Jei kompiuteriui pateiksime skaičių 2000, tai ekrane pamatysime žodį

TRUE

Aiškiau būtų, jeigu ekrane išvystume informatyvesnį pranešimą, pavyzdžiui,

OLIMPINIAI arba NEOLIMPINIAI

Apie tokių (alternatyvių) pranešimų formavimą kalbėsime 3.3 skyrelyje.

Pateiktas pavyzdys iliustruoja, kaip į ekraną rašomos loginės reikšmės. Tačiau nei Paskalio standartas, nei Turbo Paskalis nenumato loginių reikšmių skaitymo. Mat loginės reikšmės neturi visuotinai priimtų žymenų, kaip, pavyzdžiui, skaičiai. Paskalio programų tekstuose vartojami loginių reikšmių vardai true ir false gali pasirodyti per ilgi tiems kas ruošia pradinius duomenis. Todėl ten jie dažnai žymimi trumpiau (T ir F arba 0 ir 1). Tokiais atvejais rašoma loginių duomenų skaitymo programa, pritaikyta konkrečiam loginių reikšmių žymėjimui.

Uždaviniai

3.1.1. Duotas kintamųjų aprašas:

var a, b, c: integer;
x, y, z: boolean;

Kurie iš šių sakinių yra neteisingi ir kodėl?

a) x := true;
b) a := x;
c) x := a;
d) x := a - b;
e) x := c = y;
f) x := y + a;
g) c := y + 2;
h) a := b = c;
i) c := a + b.

3.1.2. Ką parašys kompiuteris pagal šitokią programą?

program logika;
  var a, b: integer;
        aa, bb, cc: boolean;
begin
  a := 3; b := 5;
  aa := a < b;
  bb := a > b;
  cc := aa;
  writeln(aa);
  writeln(aa);
  writeln(aa)
end.

3.1.3. Sakėme, kad dviguba nelygybė a<x<b su aritmetiniais duomenimis neleistina. O ar ji
         leistina su kurio nors kito tipo duomenimis?

3.1.4. Parašykite šešių loginių reikšmių lyginimo operacijų <, <=, = , <>, >, >= rezultatų
         lenteles (analogiškas konjunkcijos ir disjunkcijos lentelėms).

3.1.5. Kintamųjų reikšmės yra tokios: a = 10, b = 20, log = true, lg = false. Kokios šių
         loginių reiškinių reikšmės:

a) log or lg;
b) log and lg;
c) (a = 10) and (b = 20);
d) (a <> 10) or (b = 20);
e) (a > 5) and (b > 5) and (a < 20) and (b < 30);
f) (a > 5) and (b > 5) and (a < 10) and (b < 30);
g) (a > 5) and (b > 5) or (a < 10) and (b < 30);
h) (not (a < 15) or (not (b < 30));
i) not (a = b);
k) not (not (a = b));
l) not (not (not (a = b)))?

3.1.6. Pradiniai duomenys – trys skaičiai a, b ir c. Parašykite loginį reiškinį, kurio reikšmė
         būtų true, tada it tiktai tada, kai:

a) visų trijų kintamųjų a, b ir c reikšmės lygios;
b) visų trijų kintamųjų a, b ir c reikšmės skirtingos;
c) kurių nors dviejų kintamųjų reikšmės lygios;
d) visų trijų kintamųjų a, b ir c reikšmės yra lyginiai skaičiai;
e) visų trijų kintamųjų reikšmės yra teigiamos, bet ne didesnės kaip 100.

3.1.7. Pradiniai duomenys – keturi skaičiai a, b, c ir d. Parašykite loginį reiškinį, kurio
         reikšmė būtų true, tada it tiktai tada, kai:

a) visų keturių kintamųjų a, b, c ir d reikšmės išdėstytos didėjančiai, t.y.,
a < b < c < d

b) visų keturių kintamųjų a, b, c ir d reikšmės išdėstytos nemažėjančiai, t.y.,
a <= b <= c <= d

3.1.8. Parašykite loginį reiškinį, kurio reikšmė būtų true, jeigu iš trijų atkarpų. kurių ilgiai
         duoti (yra kintamųjų a, b, ir c reikšmės), galima surinkti:

a) trikampį,
b) lygiašonį trikampį,
c) lygiakraštį trikampį.

3.1.9. Apskritimo centro koordinatės yra cx ir cy ir spindulys r. Taško koordinatės yra tx ir
         ty. Parašykite loginį reiškinį, kurio reikšmė būtų true, jeigu taškas yra apskritimo
         viduje.

3.1.10. Elektros lemputė, pažymėta X, jungiama į tinklą per 15 paveiksle parodytą keturių
           jungiklių schemą. Jungiklių būsenos pažymėtos loginiais kintamaisiais a, b, c ir d.
           Jeigu jungiklis įjungtas (per jį teka elektros srovė), tai jį atitinkančio kintamojo
           reikšmė yra true, jei išjungtas (srovė neteka) – false. Parašykite loginį reiškinį, kurio
           reikšmė būtų true, jeigu:

a) lemputė šviečia;
b) yra trumpas jungimas schemoje;
c) lemputė nešviečia, t.y., per schemą srovė neteka.

 

 

 

15 pav.

3.1.11. Ankstesnio uždavinio schemoje lemputė pakeista laidu (16 pav.). Parašykite loginį
           reiškinį, kurio reikšmė būtų true, jeigu grandine (tarp taškų A ir B) teka elektros
           srovė.

16 pav.

3.1.12. Parašykite loginį reiškinį, kurio reikšmė būtų true, jeigu metai m keliamieji.

Ar metai keliamieji, nustatoma pagal tokias taisykles: 1) jeigu metai nėra šimtmečio metai, tai jie yra keliamieji, jeigu dalosi iš 4; 2) jeigu metai yra šimtmečio metai, tai jie yra keliamieji, jeigu šimtų skaičius dalosi iš 4 (pvz., 2000 metai yra keliamieji, o 2100 metai – ne keliamieji).

3.1.13. Turime sveikųjų skaičių tipo kintamąjį a ir šitokius loginius reiškinius:

a+1 > a
a+1 > 1
a*5 > 0
a*a > 0
a*a >= 0

Ties reiškiniu parašykite:
žodį true, jeigu jo reikšmė yra visada true;
žodį false, jeigu jo reikšmė yra visada false;
žodžius true false, jeigu gali būti vienaip ir kitaip

Praktikos darbas

3.1.1. Stačiakampis. Parašykite programą, kuri parodytų ekrane žodį TRUE, jeigu taškas yra viduje stačiakampio, kurio kraštinės lygiagrečios koordinačių ašims. Pradinius duomenis parinkite patys ir tokius, kad jų būtų kuo mažiau (pakanka 6 skaičių – trijų taškų koordinačių).

Parinkite keletą pradinių duomenų rinkinių, tokių, kad jais būtų galima visapusiškai patikrinti programą. Keletas taško padėčių stačiakampio atžvilgiu parodyta 17 paveiksle.

17 pav.

Taškui apibūdinti reikia dviejų koordinačių (tx ir ty). Stačiakampiui apibūdinti pakanka dviejų kurių nors priešingų jo kampų koordinačių (ax, cx, ay, cy).

3.2. Loginių reiškinių pertvarkymas

Pirmą kartą skaitant knygą šį skyrelį galima praleisti. Prie jo bus naudinga grįžti, kai pajusite, kad loginius reiškinius rašote per ilgus ir negražius ir norėsite juos suprastinti.

Programavime susiduriame bent su dviejų rūšių reiškiniais: aritmetiniais ir loginiais. Aritmetiniuose reiškiniuose vartojame aritmetines operacijas. Šių operacijų savybes gerai žinome. Jas išmokstame mokykloje. Jomis remdamiesi pertvarkome aritmetinius reiškinius – sutraukiame panašius narius, iškeliame bendrą dauginamąjį prieš skliaustus ir pan.

Panašios taisyklės taikomos ir loginiams reiškiniams. Tiktai loginių operacijų savybės šiek tiek skiriasi nuo aritmetinių. Todėl ir loginių reiškinių pertvarkymo taisyklės šiek tiek skiriasi (nors yra ir tokių pat) nuo aritmetinių reiškinių pertvarkymo taisyklių. Pateiksime svarbesnes.

1. Sukeitus vietomis konjunkcijos arba disjunkcijos operandus, rezultatas nepasikeičia:

a and b = b and a,
a or b = b or a.

2. Vienodos operacijos atliekamos bet kuria tvarka (vadinasi, jų operandus galime grupuoti kaip norime):

a and (b and c) = (a and b) and c,
a or (b or c) = (a or b) or c.

3. Vienodus operandus galima iškelti už skliaustų:

(a and b) or (a and c) = a and (b or c),
(a or b) and (a or c) = a or (b and c).

Pirmosios dvi taisyklės atitinka sudėties ir daugybos dėsnius. Aritmetiniuose reiškiniuose prieš skliaustus galima įkelti tik bendrus dauginamuosius, o logikoje – bet kurios operacijos (konjunkcijos arba disjunkcijos) operandų. Apskritai, kiekviena logikos taisyklė, taikoma konjunkcijai, tinka ir disjunkcijai (ir atvirkščiai). Tačiau, taikant taisyklę kitai operacijai, reikia tapatybėje (formulėje) visas operacijas ir visas konstantas pakeisti priešingomis (and => or, or => and, false => true, true => false) ir galbūt pakeisti skliaustų išdėstymą taip, kad išliktų ankstesnė operacijų atlikimo tvarka. Šis operacijų keitimo principas vadinamas dualumo principu. Jis labai praverčia besimokančiam – pakanka žinoti vieną taisyklę, o jos „antrininkę“ galima gauti taikant dualumo principą.

4. Jei operandai sutampa, tai rezultatas lygus operandui:

a and a = a,
a or a = a.

5. Jei vienas operandas konstanta, tai rezultatas lygus vienam iš operandų:

a and true = a,
a or false = a,
a and false = false,
a or true = true.

6. Konjunkciją galima pakeisti disjunkcija (ir atvirkščiai) įkeliant į skliaustus (iškeliant iš jų) inversiją:

not (a and b) = not a or not b,
not (a or b) = not a and not b.

7. Operando ir jo inversijos konjunkcijos (disjunkcijos) rezultatas yra konstanta:

a and not a = false,
a or not a = true.

8. Dvi iš eilės einančios inversijos panaikina viena kitą:

not not a = a.

1 pavyzdys. Suprastinsime loginį reiškinį

a and not b

Pritaikę 6 taisyklę gauname:
not a or not not b.

Antrajam operandui pritaikę 8 taisyklę, gauname:
not a or b.

Daug kartų pertvarkydami ilgą reiškinį, galime suklysti. Norėdami įsitikinti, ar nepadarėme klaidų, vietoj kintamųjų įrašykime į reiškinius konkrečias reikšmes ir apskaičiuokime tų reiškinių reikšmes. Jei reiškinį pertvarkėme teisingai, tai jo reikšmės prieš pertvarkymą ir po jo sutampa esant bet kokioms kintamųjų reikšmėms. Kadangi loginis kintamasis gali įgyti tik dvi reikšmes, tai reiškinį, kuriame yra n kintamųjų, reikės tikrinti 2n kartų.

2 pavyzdys. Tarkime, kad pertvarkę reiškinį

(a or b) and (a or not b) or b

gavome paprastesnį reiškinį:
a or b.

Patikrinkime, ar pertvarkydami nepadarėme klaidų, t.y. ar šių dviejų reiškinių reikšmės sutampa, esant bet kokioms jų kintamųjų a ir b reikšmėms:

 

a

b

(a or b) and (a or not b) or b

a or b

false

false

false

false

false

true

true

true

true

false

true

true

true

true

true

true

Kaip matome, visais atvejais pradinio ir pertvarkyto reiškinio reikšmės sutampa. Vadinasi, pradinis reiškinys buvo pertvarkytas teisingai.

Uždaviniai

3.2.1. Suprastinkite šiuos reiškinius:

a) not (a or b) and not (a and b)
b) a and b or not a or not (b or not a)

3.2.2. Ankstesnio skyrelio 3.2.10 uždavinio atsakyme pateikti šitokie loginiai reiškiniai:

a) a and not b and c and not d or not a and b and not c and d
b) a and b or c and d
c) not a and not b and not c and not d or not a and not d or not b or not d
    
Pabandykite juos suprastinti.

3.3. Vienas iš dviejų veiksmų

Gyvenime dažnai atsiduriame kryžkelėse, kai reikia pasirinkti, kuriuo keliu eiti. Tada žmogus sustoja, svarsto, pagaliau pasirenka.

Pasirinkimas – įprasta situacija programavime. Tiktai kompiuteris nesustoja ir nesvarsto – visi galimi keliai turi būti iš anksto numatyti ir į programą surašytos vienareikšmės jų parinkimo sąlygos.

Kompiuterio prigimtis dvejetainė. Todėl dažniausiai pasirenkamas vienas kelias iš dviejų. Vieno veiksmo iš dviejų parinkimas nurodomas sąlyginiu sakiniu, kurio pavidalas šitoks:

if loginis reiškinys then sakinys1
      else sakinys2

Po žodžio if einantis loginis reiškinys dar vadinamas sąlyga.

Atliekamas tik vienas iš dviejų sakinių:

  • sakinys, einantis po žodžio then (sakinys1), jeigu loginio reiškinio reikšmė yra true (sąlyga tenkinama) arba

  • sakinys, einantis po žodžio else (sakinys2), jeigu loginio reiškinio reikšmė yra false (sąlyga netenkinama). Sakinių pasirinkimas grafiškai pavaizduotas 18 paveiksle

18 pav. Sąlyginio sakinio schema

 

 

 

 

1 pavyzdys. Didesniojo skaičiaus radimas.

program didesnysis;
  var a, b, max: integer;
begin
  read(a, b);
  if a >= b then max := a
                 else max := b;
  writeln(max);
end.

Jei pradiniai duomenys būtų skaičiai 5 ir 6, tai būtų atliekami šie veiksmai:

                          a         b      max
read(a, b)            5         6        ?          skaitomi pradiniai duomenys
a >= b                 5         6        ?          tikrinama sąlyga
max := b             5         6        6
writeln(max)         5         5        6          rašomas rezultatas

Kad aiškiau matytųsi sąlyginio sakinio šakos, programoje jas rašome viena po kitos, t.y. žodį else lygiuojame su jį atitinkančiu pirmosios šakos žodžiu then. Kartais patogu sąlygai (su žodžiu if) skirti atskirą eilutę (ypač kai ilgesnė sąlyga), pavyzdžiui,

if (alfa*alfa) >= (beta*beta)
   then ...
   else ...

2 pavyzdys. Programa, nustatanti, ar skaičius dalus iš 7.

program dalus7;
  var x: integer;
begin
  read(x);
  write('Skaičius ', x);
  if x mod 7 = 0
     then write(' dalus')
     else write(' nedalus');
  writeln(' iš 7')
end.

Jei kompiuteriui pateiksime skaičių 12345, tai gausime atsakymą:
Skaičius 12345 nedalus iš 7

3 pavyzdys. Programa olimpinių žaidynių eilės numeriui nustatyti.

Panašų uždavinį jau sprendėme (žr. 3.1 skyr. 2 pavyzdį). Ten nustatėme, tik patį faktą, ar metai olimpiniai. Panaudodami sąlyginį sakinį galėsime nustatyti ir žaidinių eilės numerį. Neįvykusioms žaidynėms skiriamas eilės numeris, o jų metai vis tiek laikomi olimpiniais.

Pradinis duomuo – skaičius, reiškiantis metus. Rezultatas – olimpinių žaidynių numeris, jeigu metai olimpiniai, arba nulis, jeigu metai neolimpiniai.

program olimpiadanr;
  var metai,
        nr: integer; { olimpiados eilės numeris }
begin
  read(metai);
  if (metai >= 1896) and (metai mod 4 = 0)
     then nr := (metai - 1896) div 4 + 1
     else nr := 0;
  writeln(nr)
end.

Sąlyginiame sakinyje (po žodžių then ir else) gali eiti bet kokie sakiniai, tarp jų ir sąlyginiai. Tada šakos šakojasi į naujas šakas ir gaunamas medis.

4 pavyzdys. Pradiniai duomenys – trys skaičiai. Programa mažiausiam iš jų rasti.

program minimumas;
  var a, b, c, min: integer;
begin
  read(a, b, c);
  if a < b then if a < c then min := a
                                 else min := c
              else if b < c then min := b
                                 else min := c;
  writeln(min)
end.

Priklausomai nuo to, ar tenkinama sąlyga a < b, atliekama viena kuri nors gaubiančiojo sąlyginio sakinio šaka. Kiekvieną šaką sudaro naujas sąlyginis sakinys, turintis dvi šakas (19 pav).

19 pav. Veiksmų šakojimasis 3 pavyzdžio sąlyginiame sakinyje

Nebūtinai kiekvienas sąlyginis turi būti simetriškas – viena sąlyga gali šakotis daugiau, kita – mažiau.

Lengviau parašyti ir suvokti tokį nesimetrišką sąlyginį sakinį, kuriame veiksmai šakojasi tik po else. Šitaip nuo daugelio galimų kelių (galbūt iki galo dar neišnagrinėtų) atskiriamas vienas, kurio veiksmai jau aiškus ir tie veiksmai užrašomi po then, o visa kita, kas dar toliau lieka skaldyti į šakas, rašoma po else.

5 pavyzdys. Užrašysime sakinius kintamojo y reikšmei, kuri priklauso nuo kintamojo x reikšmės ir apskaičiuojama pagal šitokią formulę:

0,          jei x < -10,
10 + x,   jei -10 <= x <= -5,
y = 5,    jei -5 < x < 5,
10 – x,   jei 5 <= x <= 10,
0,          jei x > 10.

Kaip kintamojo y reikšmė priklauso nuo kintamojo x reikšmės, rodo grafikas (20 pav.).


20 pav.

Sąlyginiu sakiniu ta priklausomybė išreiškiama taip:

if x < -10 then y := 0
   else if x <= -5 then y := 10 + x
      else if x < 5 then y := 5
         else if x <= 10 then y := 10 - x
                                else y := 0

Veiksmų šakojimasis grafiškai pavaizduotas 21 paveiksle.

21 pav.

 

Pastebėsime, kad sąlygos, einančios po žodžių else if, paprastesnė už sąlygas, esančias uždavinio formulėje. Mat kintamojo x reikšmės rėžį pakanka tikrinti tik iš vienos pusės – iš kitos pusės jis jau buvo patikrintas prieš patenkant į tą sakinio šaką.

Sąlyginis sakinys, kuriame po žodžių else įterpiami vis nauji sąlyginiai sakiniai, žodžius else lygiuojant su juos atitinkančiais then, labai išsitęstų į dešinę. Programos vaizdumas nenukenčia, jeigu sakinio dalis, prasidedančias žodžių pora else if, rašome šiek tiek patrauktas į dešinę.

Uždaviniai

3.3.1. Kokios bus kintamųjų a ir b reikšmės, atlikus šitokią sakinių seką?

a := 10; b := 6;
if a > b then a := a - b;
            else a := a + 3;
if a > 6 then b := b + 1
            else b := b + 2

3.3.2. Atlikus sakinį

if a > b then a := a - b
            else b := b - a

gautos šitokios kintamųjų a ir b reikšmės: a = 5, b = 5. Kokios galėjo būti šių kintamųjų reikšmės, prieš atliekant sąlyginį sakinį.

3.3.3. Turime tokią programą mažiausiam iš trijų skaičių rasti.

program minim;
  var a, b, c, min: integer;
begin
  read (a, b, c);
  if (a < b) and (a < c) then min := a
     else if (b < c) and (b < a) then min := b
                                            else min := c;
  writeln(min)
end.

Ar ji teisinga? Jei taip, ar ji visada duos tokį pat rezultatą, kaip ir programa minimumas (žr. 3 pavyzdį).

3.3.4. Parašykite sąlyginį sakinį rezultato f reikšmei rasti pagal formulę

f = a + b,   jei a – nelyginis,
a * b,         jei a – lyginis.

3.3.5. Duotas sąlyginis sakinys

if a < 3
   then c := 1
   else if a > = 5 then c := 2
                         else c := 3

Kokiai kintamojo a reikšmei esant, kintamajam c bus priskirta reikšmė 3?

3.3.6. Programą olimpiadanr pakeiskite taip, kad būtų spausdinamas šitokio pavidalo
          tekstas:

1999 metai yra neolimpiniai
2000 metai yra olimpiniai

3.3.7. Programoje dalus7 į ekraną rašomo teksto eilučių pradžiose ir pabaigose yra tarpų.
         Kam jie reikalingi? Kaip atrodytų rašomas į ekraną tekstas, jeigu juos pašalintume?

3.3.8. Parašykite programą, kuri atliktų tokius veiksmus su pradiniu duomeniu: jeigu jis
         teigiamas, tai jį paverstų tokio pat modulio neigiamu skaičiumi, jeigu neigiamas –
         paverstų jo moduliu.

Praktikos darbas

3.3.1. Programos atlikimas pažingsniui. Programą minimumas (žr. 4 pavyzdį) papildykite dialogo veiksmais ir išbandykite su kompiuteriu, kai pradiniai duomenys yra šitokie:

  5     6    10
  5     6      2
25    17    18
25    17    16

Stebėkite kokie sakiniai kokiu atveju yra atliekami. Tam panaudokite pažingsninį kompiliatoriaus režimą.

Tą patį padarykite su programa olimpiadanr (žr. 3 pavyzdį). Pradinius duomenis programos išbandymui pasirinkite patys.

3.4. Įvairesni šakojimosi atvejai

Ne visada visi šakos veiksmai išreiškiami vienu sakiniu. Būna atvejų, kai reikia rašyti kelis sakinius, o kartais šaka būna tuščia – be jokių veiksmų. Tokius atvejus ir panagrinėsime.

Tuščias sakinys. Dažnai veiksmą reikia atlikti tik vienu atveju (pavyzdžiui, kai sąlyga tenkinama), o priešingu atveju nereikia nieko daryti. Pavyzdžiui, jeigu reikia kintamojo a reikšmę pakeisti jos moduliu, tai skaičiaus ženklą reikia keisti tik tada, kai jis neigiamas, o jeigu jis teigiamas, tai nereikia nieko daryti. Tokius veiksmus galima užrašyti bet kuriuo iš tokių sąlyginių sakinių:

if a < 0 then a := -a
           else;
arba

if a >= 0 then
             else a := -a

Ten, kur nereikia atlikti veiksmų, nieko ir nerašome. Tokia tuščia vieta vadinama tuščiu sakiniu. Pirmuoju atveju tuščias sakinys „parašytas“ po else, antruoju – po then.

Sakiniai skiriami kabliataškiais. jeigu netyčia tarp gretimų dviejų sakinių parašysime ne vieną, o du (ar kelis) kabliataškius, tai klaidos nebus – bus laikoma, kad tenai, tarp kabliataškių yra tušti sakiniai.

Sutrumpintas sąlyginis sakinys. Kai tuščias sakinys yra po else, tai galima praleisti ir žodį else, pavyzdžiui,

if a < 0 then a := -a

Šitokia Paskalio kalbos konstrukcija sutrumpintu sąlyginiu sakiniu. Jo bendrasis pavidalas yra šitoks:

if loginis reiškinys then sakinys

Sutrumpinto sąlyginio sakinio schema pateikta 22 paveiksle.

Vienas į kitą įdėti sutrumpinti sąlyginiai sakiniai. Tarkime, kad turime šitaip netvarkingai į vieną eilutę surašytus vienas į kitą įdėtus sakinius:

if b1 then if b2 then S1 else S2

Kuriam sakiniui priklauso šaka else S2: pirmajam (if b1 then), ar antrajam (if b2 then). Paklausti galima ir kitaip: kurį then atitinka else, arba kuris iš šių dviejų vienas į kitą įdėtų sąlyginių sakinių yra sutrumpintas?

 

 

22 pav. Sutrumpinto sąlyginio sakinio schema

 

Yra susitarta tokį užrašą interpretuoti šitaip:

if b1
   then if b2
              then S1
              else S2

T.y., vidiniai sakiniai laikomi (jeigu tik galima) nesutrumpintais.

Sudėtingesniam sąlyginiam sakiniui perskaityti galime rekomenduoti paprastą taisyklę – trūkstamus else surašyti sakinio gale. Tuomet nesunkiai ir vienareikšmiškai atrandami žodžių if, then ir else trejetai.

Vadinasi, sakinį

if b1 then if b2 then if b3 then S1 else S2

reikia suprasti šitaip:

if b1
   then if b2
              then if b3 then S1
                             else S2
              else
   else

Kai norime parašyti sudėtingesnį sakinį, galime rekomenduoti pradžioje surašyti visus else, sakinius taisyklingai sulygiuoti, o po to nereikalingus else išbraukti.

Sudėtinis sakinys. Kalbėdami apie sakinius, rašomus į bet kurią sąlyginio sakinio šaką, vartojome vienaskaitą. O ką daryti, kai vienu ar kitu atveju reikia atlikti ne vieną, o kelis sakinius?

Tada tie keli sakiniai rašomi tarp žodžių begin ir end. Šitaip sakinių grupė paverčiama vienu sakiniu, kuris vadinamas sudėtiniu. Jo schema yra tokia:

begin
  sakinys1;
  sakinys2;
  ...
  sakinysn
end

Sudėtinis sakinys – tai vienas sakinys, kurį galima rašyti visur ten, kur ir bet kurį paprastą sakinį.

1 pavyzdys.

if a < 0 then begin
                      b := b + 1; c := c + 1
                    end
           else begin

                     b := b - 1; c := c - 1
                   end

Kad būtų geriau matomos sudėtinio sakinio ribos, žodžiai begin ir end rašomi vienas po kitu ir vienodai atitraukiami nuo kairiojo eilutės krašto, o jiems priklausantys sakiniai truputį patraukiami į dešinę. Trumpo sudėtinio sakinio ribos gerai matomos ir tada, kai visas jis parašytas vienoje eilutėje, pavyzdžiui,

if a < 0
   then begin b := b + 1; c := c + 1 end

2 pavyzdys. Pradiniai duomenys – du skaičiai. Rezultatas apskaičiuojamas pagal formulę

s = x2 + y3;
čia x – didesnysis, o y – mažesnysis pradinis duomuo.

Sudarome programą:

program p;
  var a, b, x, y: integer;
begin
  read(a, b);
  if a < b
     then begin x := b;
                       y := a
             end
     else begin x := a;
                       y := b
             end;
  writeln(x*x + y*y*y)
end.

Sudėtinį sakinį gali sudaryti daugelis kitokių sakinių, tarp jų gali būti sąlyginių ir trumpesnių sudėtinių sakinių.

Kiekvienos programos veiksmų dalį sudaro sakiniai, parašyti tarp žodžių begin ir end. Taigi būsime teisūs, jeigu sakysime, kad kiekvienos programos visi veiksmai išreiškiami vieninteliu sudėtiniu sakiniu.

Skyrybos klaidos. Atkreipiame dėmesį į tai, kad prieš žodį else kabliataškio rašyti negalima. Jeigu jį ten padėtume, tai reikštų, kad po kabliataškio eina jau kitas sakinys (kabliataškis skiria sakinius), pvz.:

if b then S1; else S2

Kadangi žodžiu else negali prasidėti joks sakinys, tai tokią klaidą pastebės Turbo Paskalio kompiliatorius.

O jeigu sakinyje

if b then S

netyčia padėtume kabliataškį po žodžio then:

if b then; S

tai programa liktų taisyklinga – būtų laikoma, kad po then yra tuščias sakinys, kabliataškis atskiria sakinį S nuo sąlyginio. Sakinys S nebepriklauso sąlyginiam ir atliekamas visada. Tokios klaidos kompiliatorius nerastų, o mes stebėtumės, kodėl kompiuteris duoda ne tokį rezultatą, kokio tikimės.

Uždaviniai

3.4.1. Duota programa

program mini;
  var a, b, c, min: integer;
begin
  read(a, b, c);
  min := a;
  if b < min then min := b;
  if c < min then min := c;
  write(min)
end.

Ar visada kompiuteris išspausdins vienodus rezultatus, atlikęs programą minim ir minimumas (žr. 3.3 skyr., 4 pavyzdį), kai pradiniai duomenys tie patys?

3.4.2. Parašykite sąlyginius sakinius, pagal kuriuos būtų palyginamos kintamųjų a ir b
         reikšmės ir, jeigu jos nelygios:

a) iš didesniosios atimama mažesnioji;
b) mažesnioji padidinama vienetu;
c) didesnioji sumažinama vienetu.

3.4.3. Duota programa

program skaitymas;
  var a, b, c, d: integer;
begin
  read(a, b);
  if a < b
     then read(c, d)
     else if a > b
                then read(d, c);
  write(a, ' ', b, ' ', c, ' ', d)
end.

Pradiniai duomenys šitokie:
a) 1   2   3   4
b) 4   3   2   1

Ką išspausdins kompiuteris?

Nors ir apskaičiavote rezultatą, bet programa yra neteisinga: gali būti tokių pradinių duomenų, kuriems esant bus vartojamos neapibrėžtos kintamųjų reikšmės. Kokiems pradiniams duomenims esant tai atsitiks?

3.4.4. Pavartodami sudėtinius sakinius, suprastinkite šį programos fragmentą:

if a > b   then c := 1;
if a > b   then d := 2;
if a <= b then c := 3;
if a <= b then d := 4

3.4.5. Duota programa:

program pp;
  var a, b, xx, yy, s: integer;
begin
  read(a, b);
  xx := a*a;
  yy := b*b;
  if a < b then xx := xx*a
             else yy := yy*b;
  s := xx + yy;
  write(s)
end.

Ar programa pp atlieka tokius pat veiksmus, kaip ir 2-ojo pavyzdžio programa p?

3.4.6. Duoti du sudėtiniai sakiniai:

a) begin
      c := 0;
      if a < 5 then c := 1;
      if a > 5 then c := 2
    end;

b) begin
      c := 0;
      if a < 5 then c := 1
                  else c := 2
    end

Ar atlikus šiuos sakinius visada rezultatas (kintamojo c reikšmė) yra tas pats? Jeigu ne, tai su kuria kintamojo a reikšme jie skiriasi?

3.4.7. Duota programa:

program perdaug;
  var a, b: integer;
begin
  read(a, b);
  if a < 10 then begin a := 10;
                                 b := b - 5
                       end;
  if a < 5 then begin a := 5;
                               b := b - 5
                     end;
 
writeln(a, b: 6)
end.

Sutrumpinkite ją, pašalindami vieną nereikalingą sakinį.

3.4.8. Duota programa:

program intervalai;
  var a, b, c: integer;
begin
  read(a, b, c);
  if a < 0 then a := 2 - a;
  if b < 0 then b := 10;
  if c > 10 then c := 10;
  writeln(a, ' ', b, ' ', c)
end.

Nustatykite, kokiuose intervaluose bus rezultatų reikšmės. Intervalus nurodykite nelygybėmis. (Kokie rezultatai bus išspausdinti, be abejo, priklauso nuo pradinių duomenų. Tačiau ir nežinant jų, vien iš programos teksto galima šį tą pasakyti apie rezultatus.)

3.4.9. Taikydami logines operacijas, suprastinkite šiuos sakinius:

a) if a > b then
       if b < c then a := a + 1;

b) if log then
            else a := a + 1;

3.4.10. Programą dalus (žr. 3.3 skyr. 3 pavyzdį) pakeiskite taip, kad joje būtų tik vienas
           suprastintas sąlyginis sakinys.

Praktikos darbas

3.4.1. Vidurinysis skaičius. Pradiniai duomenys – trys sveikieji skaičiai. Parašykite programą, kuri rastų vidurinįjį skaičių, jeigu tie skaičiai būtų surikiuoti eilės tvarka (nemažėjančiai arba nedidėjančiai). Pateikiame keletą pavyzdžių.

Pradiniai duomenys        Rezultatas
33          55        22              33
22          33        22              22
22          33        33              33
55          55        55              55

3.5. Lygčių sprendimai su pradinių duomenų tyrimu

Turėdami sąlyginį sakinį galime ištirti pradinius duomenis. Tai ypač patogu rašyti lygčių sprendimo programas, kai pirmiausia reikia ištirti kiek ir kokių sprendinių turi lygtis.

Kvadratinė lygtis

ax2 + bx + c = 0.

Šaknys randamos pagal formulę

        -b ± Vb2 - 4ac
x = ––––––––––––––––
                 2a

Reiškinys

D = b2 - 4a

vadinamas kvadratinės lygties diskriminantu. Kai D < 0, tai lygtis neturi šaknų, kai D = 0, tai lygtis turi vieną šaknį, kai D > 0, tai lygtis turi dvi šaknis. Taigi, programoje reikia pirmiausiai apskaičiuoti determinantą, nustatyti, kiek lygtis turi šaknų ir rasti jas.

program kvlygtis;
  const paklaida = 0.00001;
  var a, b, c,                          { lygties koeficientai }
        D,                                 { diskriminantas }
        x1, x2: real;                   { šaknys }
begin
  read(a, b, c);
  D := b*b - 4*a;
  if abs(d) <= paklaida
     then writeln('x = ', -b / (2*a): 10: 2)
     else if D > paklaida
                then begin
                          writeln('x1 = ', (-b + D) / (2*a));
                          writeln('x2 = ', (-b - D) / (2 * a))
                        end
                else writeln('Lygtis sprendinių neturi')
end.

Programoje tikrinama, ar diskriminantas D nedidesnis už labai mažą dydį paklaida, vietoj matematikoje įprasto patikrinimo, ar jis lygus nuliui. Mat matematikoje laikoma, kad visi dydžiai yra absoliučiai tikslūs. Tuo tarpu kompiuteryje realieji skaičiai vaizduojami apytiksliai. Dėl paklaidų vietoj nulio gali atsirasti labai mažas skaičius, artimas nuliui, bet nelygus jam. Taip atsitinka ne visada, bet gera programa turi nepriekaištingai veikti su visais pradiniais duomenimis. Dėl to panaudojome konstantą paklaida.

Praktikos darbai

3.5.1. Dviejų tiesinių lygčių sistema

a1x + b1y = c1
a2x + b2y = c2

Rankiniu būdu lygtį sprendžiame taikydami įvairius metodus: keitimo, sudėties, įvesdami naujus kintamuosius ir pan. Pasirenkame patogesnį (reikalaujantį mažiau veiksmų) metodą konkrečiai lygčių sistemai spręsti priklausomai nuo jos koeficientų. Programa turėtų būti universali ir tikti bet kokiai lygčių sistemai spręsti. Veiksmų kiekis kompiuteriui mažiau svarbus, negu žmogui. Todėl reikėtų pasirinkti kurį nors vieną metodą, tinkamesnį programavimui. Toks metodas yra. Dviejų tiesinių lygčių sistemos šaknį galima rasti pagal formules.

Pirmiausiai apskaičiuojami lygčių sistemos determinantai (nepainiokime su kvadratinės lygties diskriminantu)

D = a1b2 - a2b1,
Dx = c1b2 - c2b1,
Dy = a1c2 - a2c1.

Jeigu D = 0 ir kuris nors iš Dx arba Dy nelygus nuliui, tai lygčių sistema nesuderinama ir sprendinių neturi.

Jeigu D = Dx = Dy = 0, tai lygtys priklausomos ir jų sistema turi be galo daug sprendinių.

Jeigu netenkinama nė viena iš minėtų sąlygų, tai lygties sprendiniai egzistuoja ir juos galima rasti pagal šias formules:

x = Dx / D;
y = Dy / D

Šitaip galima išspręsti ne tik dviejų lygčių sistemą su dviem nežinomaisiais, bet n tiesinių lygčių sistemą su n nežinomųjų.

Parašykite programą dviejų tiesinių lygčių sistemai spręsti.

3.5.2. Bikvadratinė lygtis

ax4 + bx2 + c = 0

sprendžiama įvedant pagalbinį kintamąjį

y = x2

Tada sprendžiama kvadratinė lygtis

ay2 + by + c = 0

o iš jos sprendinių gaunami bikvadratinės lygties sprendiniai.

Parašykite programą bikvadratinei lygčiai spręsti.

3.6. Veiksmų kartojimas. Ciklai while ir repeat

Programose būna veiksmų, kuriuos reikia kartoti. Dažniausiai veiksmai yra tie patys, tik juos kartoti reikia vis su kitais duomenimis.

Kartojimo veiksmai užrašomi ciklais. Paskalis turi trijų rūšių ciklus. Jų antraštės prasideda baziniais žodžiais while, for ir repeat. Todėl programuotojai kartais ciklus taip ir vadina šiais baziniais žodžiais.

Ciklas while. Kartojimo veiksmus taikliausiai aprašo while ciklas. Tai ir pats paprasčiausias ciklas. Jo veikimas grafiškai pavaizduotas 23 paveiksle, o programoje užrašomas šitaip:

while loginis reiškinys do
  sakinys

23 pav. Ciklo while schema

 

Pirmoji eilutė – ciklo antraštė. Po jos (t.y. po žodžio do) einantys sakinys kartojamas tol, kol tenkinama ciklo antaštėje užrašyta sąlyga (kol loginio reiškinio reikšmė yra true).

 

 

1 pavyzdys. Programa pirmajam reikšmingam (t.y., nelygiam nuliui) skaičiaus skaitmeniui rasti.

program pirmasis;
  var sk: integer;
begin
  read(sk);
  while sk > 9 do
    sk := sk div 10;
  writeln(sk)
end.

Šis uždavinys toks akivaizdus žmogui, kad jo netgi nelaikome uždaviniu – iš karto matome, koks pirmasis skaičiaus skaitmuo. Tuo tarpu kompiuteryje skaičius būna užrašytas dvejetainiais skaitmenimis ir kompiuteris dešimtainių skaičiaus skaitmenų „nemato“, lygiai taip, kaip mes nematome dvejetainių jo skaitmenų. Ir dar svarbiau – užduotis kompiuteriui gali būti išreiškiama tik tomis operacijomis, kurios yra programavimo kalboje. O Paskalis turi tik aritmetines skaičių operacijas.

Paseksime, kaip šis ciklas atliekamas su įvairiais pradiniais duomenimis.

Pradinis duomuo: 625.

                                          sk                      Sąlyga
read(sk)                               625
sk > 9                                                             true
sk := sk div 10                       62
sk > 9                                                              true
sk := sk div 10                         6
sk > 9                                                              false
writeln(sk)

Ciklas buvo atliktas du kartus.

Jeigu pradinis duomuo būtų dviženklis skaičius, ciklas būtų atliktas vieną kartą. Jeigu pradinis duomuo būtų vienženklis skaičius, ciklas nebūtų atliktas nė vieno karto – rezultatas būtų lygus pradiniam duomeniui.

Prieš kiekvieną sakinio kartojimą, perskaičiuojama loginio reiškinio reikšmė ir pagal ją nustatoma, ar dar reikia kartoti sakinį, ar jau užbaigti ciklą. Jeigu sąlyga netenkinama (reiškinio reikšmė false) tikrinant ją pirmą kartą, tai po žodžio do einantis sakinys neatliekamas nė karto. Taigi galima tvirtinti, kad ciklas while gali būti atliekamas 0, 1, 2 ir daugiau kartų.

Ciklas valdo vieno sakinio kartojimą. Jeigu reikia kartoti kelis sakinius, tai tie sakiniai sujungiami į vieną sudėtinį sakinį.

2 pavyzdys. Programa skaičiaus skaitmenų sumai rasti.

program SkSuma;
  var sk, suma: integer;
begin
  suma := 0;
  read(sk);
  while sk > 0 do
    begin
      suma := suma + sk mod 10;
      sk := sk div 10
    end;
  writeln(suma)
end.

3 pavyzdys. Programa klasės mokinių pažymių vidurkiui rasti.

program pvidurkis;
  var msk,                        { mokinių skaičius }
        p,                             { vieno mokinio pažymys }
        psuma: integer;         { visų mokinių pažymių suma }
        pbyla: text;                { pažymių byla }
begin
  assign(pbyla, 'PAŽYMIAI.TXT'); reset(pbyla);
  msk := 0;
  psuma := 0;
  read(pbyla, p);
  while p > 0 do
    begin
      psuma := psuma + p;
      msk := msk + 1;
      read(pbyla, p)
    end;
  writeln(psuma/msk: 8: 2)
end.

Paeiliui skaitomi ir sudedami mokinių pažymiai. Kartu skaičiuojamas ir mokinių (pažymių) skaičius msk. Ciklas kartojamas tol, kol skaitomi pažymiai didesni už nulį. Todėl čia nulis yra sutartinis ženklas. Juo užbaigiamas pažymių sąrašas. Kai perskaitomas nulis, kompiuteris supranta, kad jau perskaityti visi pradiniai duomenys (visų mokinių pažymiai), ciklą reikia baigti ir jau galima skaičiuoti vidurkį. Nulis – tai tik vienas iš daugelio būdų nurodyti sąrašo pabaigai. Jis tinka tada, kai sąraše nėra nulių. Šiam tikslui mes jį galėjome panaudoti tik todėl, kad laikėme, kad pažymių, lygių nuliui, nebūna.

Ar kiekvienas ciklas turi pabaigą? Tam, kad ciklas baigtųsi, reikia, kad jo antraštėje užrašyto loginio reiškinio reikšmė kada nors taptų false. Vadinasi, loginio reiškinio komponentus turi keisti sakinys. Priešingu atveju loginio reiškinio rekšmė visą laiką išliks true ir ciklas niekada nesibaigs. Toks ciklas vadinamas amžinuoju.

4 pavyzdys. Amžinasis ciklas kai nekeičiami loginio reiškinio komponentai.

while a < b do
  write(a)

5 pavyzdys. Amžinasis ciklas kai ne ta linkme keičiami loginio reiškinio komponentai.

while a < b do
  b := b + 1

Amžinasis ciklas yra dažnai pasitaikanti klaida. Jeigu programa įtartinai ilgai veikia, tai galima tikėtis, kad kompiuteris atlieka amžinąjį ciklą. Tokiu atveju programos darbą reikia priverstinai nutraukti (daugelyje kompiuterių – paspausti klavišus Ctrl+Break) ir ieškoti klaidos – amžinojo ciklo.

Ciklas repeat. Kitas, rečiau vartojamas ciklas yra vadinamas repeat ciklu. Jo pavidalas yra šitoks:

repeat
  sakinys1;
  sakinys2;
  ...
  sakinysn
until loginis reiškinys

Sakiniai, esantys tarp žodžių repeat ir until, kartojami iki tol, kol bus patenkinta sąlyga – loginio reiškinio reikšmė taps true.

Ciklo veiksmai grafiškai parodyti 24 paveiksle.

 

 

 

24 pav. Ciklo repeat schema

6 pavyzdys. Programa, skaičiuojanti sumą skaičių sekos, kurios paskutinis skaičius sutampa su pirmuoju. Skaičiai renkami klaviatūra.

program suma;
  var sk,                         { skaitomas skaičius }
        pirmas,                   { pirmas perskaitytas skaičius }
        sum: integer;           { suma }
begin
  read(pirmas);
  sum := pirmas;
  repeat
    read(sk);
    sum := sum+sk
  until sk = pirmas;
  writeln(sum)
end.

Cikle repeat pirma atliekami veiksmai, o po to tikrinama sąlyga. Dėl to ciklas visada atliekamas bent vieną kartą. Taigi galima tvirtinti, kad ciklas repeat gali būti atliekamas 1, 2, 3 ir daugiau kartų.

Ciklas repeat baigiamas, kai tenkinama jo pabaigoje (po žodžio until) parašyta sąlyga. Tuo tarpu ciklas while baigiamas kai nebetenkinama jo pradžioje parašyta sąlyga. Šios dvi priešingybės kartais supainiojamos ir programuotojas suklysta. Galime pasiūlyti tokį lengviau įsimenamą sąlygų tikrinimo modelį. Vietoj sąlygų įsivaizduokime šviesoforus. Kai sąlyga tenkinama, šviesoforas žalias, kai netenkinama – raudonas.

Šviesoforas stovi ciklo while pradžioje. Vadinasi, patekti į ciklą galima kai šviesoforas žalias – sąlyga tenkinama.

Šviesoforas stovi ciklo repeat pabaigoje. Vadinasi, jis reguliuoja išvažiavimą iš ciklo. Taigi ciklą palikti galima kai šviesoforas žalias – sąlyga tenkinama.

Žodis until atlieka ir skyrybos ženklo vaidmenį – parodo, kur baigiasi ciklo sakiniai. Dėl to cikle repeat galima rašyti daugelį sakinių – nereikia jų „apskliausti“

Uždaviniai

3.6.1. Kokia bus kintamojo x reikšmė, atlikus šitokias sakinių sekas?

a) k := 1;
    while k < 5 do
      k := k + 1;
    x := k

b) x := 1;
    while x <= 5 do
      x := x + 1;

3.6.2. Duota sakinių seka

a := 1; b := 1;
while a+b < 8 do
  begin
    a := a+1;
    b := b+2
  end;
s := a+b

Kiek kartų bus atliekamas ciklas ir kokios bus kintamųjų a, b ir s reikšmės, atlikus duotąją sakinių seką?

3.6.3. Kokios bus kintamųjų a ir b reikšmės, atlikus šią sakinių seką:

a := 1; b := 1;
while a <= 3 do
  a := a+1; b := b+1

3.6.4. Parašykite programą, kuri rastų mažiausią skaičių byloje SKAIČIAI.TEK.

Praktikos darbas

3.6.1. Rezultatų kaita atliekant programą. 3 pavyzdžio programą pvidurkis modifikuokite taip, kad ji apskaičiuotų per pamoką gautų mokinių pažymių vidurkį dinamiškai, t.y., pažymių sąrašas papildomas, kai tik pažymį gauna nauja mokinys ir kiekvieną kartą ekrane parodomas naujas, pakoreguotas vidurkis. Atlikite ją kompiuteriu.

3.7. Valdymo struktūrų palyginimas

Prieskyros, duomenų skaitymo bei rašymo ir tuščias sakinys yra elementarūs, nedalomi. Į juos negali įeiti jokie kiti sakiniai.

Sakinių atlikimo tvarką nustato struktūriniai sakiniai – sudėtinis, sąlyginis ir ciklo. Jie sudaromi iš elementarių ir trumpesnių struktūrinių sakinių.

Kelių sakinių seką sudėtinis sakinys paverčia vienu sakiniu. Todėl visur ten, kur pagal programavimo kalbos taisykles gali būti rašomas tik vienas sakinys, o norisi rašyti kelis sakinius, tuos kelis sakinius reikia sujungti į vieną sudėtinį, ir problema bus išspręsta.

Visą programą sudaranti sakinių seka taip pat jungiama į vieną sudėtinį sakinį. Taigi galima tvirtinti, kad visos programos veiksmai išreiškiami vienu sudėtiniu sakiniu. Žinoma, tas sakinys gali būti sudėtingas ir ilgas – užimti daug puslapių.

Sąlyginis sakinys išrenka vieną kurią nors programos šaką. Kitos šakos sakiniai neatliekami. Vadinasi, kompiuteris atlieka mažiau sakinių negu jų yra programoje.

Ciklų sakiniai nurodo, kad reikia ciklo sakinius kartoti daug kartų. Vadinasi, kai programoje yra ciklų, kompiuteriui gali tekti atlikti daugiau veiksmų negu jų yra parašyta programoje.

Struktūriniai sakiniai dar vadinami valdymo struktūromis, nes jais išreiškiami nurodymai, kaip valdyti kitų sakinių atlikimo tvarką. Visos nagrinėtos valdymo struktūros yra lygiateisės: jos gali įeiti viena į kitą. Nuosekli sakinių seka jau buvo pakeista vienu sudėtiniu sakiniu, įeinančiu į ciklą arba sąlyginį sakinį. Patys sąlyginiai sakiniai arba ciklai buvo eiliniai nuoseklios sakinių sekos nariai. Ciklas taip pat gali būti kitame cikle arba sąlyginiame sakinyje be jokių ribojimų.

1966 m. C. Bohmas ir G. Jacopinis įrodė, kad kiekvieną elementarių sakinių atlikimo tvarką galima aprašyti trimis valdymo struktūromis: sakinių seka, sąlyginiu sakiniu ciklu. Pakanka tik vienos rūšies (nesuprastinto) sąlyginio sakinio ir vienos rūšies (while) ciklo. Kiti (alternatyvūs) struktūriniai sakiniai nėra būtini. Tačiau jie sutrumpina programą arba padaro ją vaizdesnę. Prieš rašant struktūrinį sakinį reikia pagalvoti, kurią iš galimų alternatyvių valdymo struktūrų naudoti. Pasirinkus tinkamą struktūrą, programa bus trumpesnė, ją bus lengviau skaityti.

Uždaviniai

3.7.1. Kurie iš šių teiginių teisingi?

a) ciklas prasidedantis žodžiu while gali būti neatliktas nė vieno karto;
b) ciklas prasidedantis žodžiu repeat gali būti neatliktas nė vieno karto;
c) ciklas prasidedantis žodžiu while arba repeat gali būti atliktas vieną kartą.

3.7.2. Palikite vieną iš skliaustuose parašytų alternatyvų:

Ciklo sakinys, prasidedantis žodžiu while valdo (vieno sakinio / sakinių sekos) kartojimą, o ciklo sakinys, prasidedantis žodžiu repeat valdo (vieno sakinio / sakinių sekos) kartojimą.

3.8. Begalinių eilučių sumavimas

Daugelį matematikos konstantų arba funkcijų galima išreikšti begalinių eilučių suma. Pateiksime pavyzdžių:

            1      1     1               1
e = 1 + — + — + — + . . . + — . . .
            1!     2!    3!              n!

              x     x2    x3             xn
ex = 1 + — + — + — + . . . + — . . .
              1!    2!     3!              n!

(e – natūrinių logaritmų pagrindas)

 p          1     1     1           xn
 – = 1 - — + — - — + . . . — . . .
 4          3     5     7           n!

                   x3    x5     x7
arctg x = x - — + — - — +
                    3     5!    7!

Kuo daugiau eilutės narių sudėsime (kompiuteriui nesunku sudėti jų labai daug), tuo tikslesnę reikšmę gausime. Kiek jų reikia sudėti, programoje galima nurodyti įvairiai. Paprasčiausia sumuoti tam tikrą iš anksto nustatytą pirmųjų narių skaičių. Tačiau programos dažniausiai sudaromos taip, kad būtų sumuojami eilutės nariai tol, kol jie pasidaro mažesni už tam tikrą, labai mažą, iš anksto pasirinktą dydį. Šis dydis ir apibūdina paklaidą.

Pavyzdys. Sudarysime programą natūrinių logaritmų pagrindui e rasti.

program logaritmas;
  const epsilon = 1E-6;        { liekamasis narys }
  var k : integer;
        e, narys: real;
begin
  e := 0.0;
  narys := 1.0;
  k := 1;
  while narys >= epsilon do
    begin
      e := e + narys;
      narys := narys/k;     { 1/1 }
                                    {1/1/2 = 1/(1*2)}
                                    {1/1/2/3 = 1/(1*2*3)}
                                    { . . . }
      k := k + 1
    end;
  writeln(e)
end.

Šioje programoje skaičiaus faktorialas neskaičiuojamas išreikštiniu būdu. Eilinis eilutės narys gaunamas ankstesnį jos narį padalijus iš vieno po kito einančių natūraliųjų skaičių. Taip išvengiama didelių skaičių faktorialų reikšmių, kurios gali netilpti į sveikųjų skaičių rėžius.

Kompiuteris, atlikęs programą logaritmas, pateikė šitokį rezultatą:
2.7182815256E+00

Palyginimui pateikiame tikslesnę skaičiaus e reikšmę:
2,7182818284.

Programose, kurių rezultatai yra sveikieji skaičiai, reikia vengti realiųjų skaičių, nse operacijos su jais rezultatai yra apytiksliai skaičiai ir gali iškreipti tikrąjį rezultatą. Pavyzdžiui, jei skaičiuodami sklypo plotą vietoj 8191 m2 gauname 8191,5 m2 arba 8191 m2, tai į tokia menkas paklaidas galime nekreipti dėmesio. Tuo tarpu jeigu pirminių skaičių ieškojimo programoje vietoj 8191 gautume 8192, tai toks rezultatas ir jį duodanti programa būtų klaidingi.

Uždaviniai

3.8.1. Parašykite programą funkcijos ex reikšmei rasti, taikydami skyrelio pradžioje pateiktą
         eilutės sumavimo formulę.

3.8.2. Parašykite programą skaičiaus p reikšmei rasti, taikydami skyrelio pradžioje pateiktą
         eilutės sumavimo formulę. Sumuoti reikia tol, kol eilutės nario modulis bus mažesnis
         už 1010.

E Ankstesnis puslapis

3 Turinys

Kitas puslapis F

tus0.gif (69 bytes)