tus0.gif (69 bytes)
 

ELEKTRONINĖS KNYGOS

tus0.gif (69 bytes)

Gintautas GRIGAS
PROGRAMAVIMAS PASKALIU

6. PROGRAMOS SKAIDYMAS Į DALIS

Didelių darbų neįveiktume, jeigu nemokėtume padaryti mažų darbų. Kiekvienas didelis darbas susideda iš daugelio mažų darbų. Ir tūkstančio mylių kelionė prasideda vienu žingsniu – sako kinų patarlė. Reikia tik mokėti darbą suskaidyti į dalis, o padarius mažesnes dalis – jas sujungti į darnią visumą – didelio darbo rezultatą.

Uždavinio dalių programos išreiškiamos funkcijomis ir procedūromis. Po to jos sujungiamos į programą ir gaunama darni viso uždavinio programa.

Ta pati funkcija ar procedūra gali būti panaudota įvairiose programose, panašiai, kaip bet kurio mechanizmo (pvz., laikrodžio, televizoriaus) keičiamas mazgas arba detalė.

6.1. Funkcijos ir procedūros

Paprastesnių uždavinių programos būna trumpos, vaizdžios. Turinčiam įgūdžių jas parašyti nesunku. Jau esame sudarę keliolikos paprastų uždavinių programas ir matėme, kad kiekviena jų yra savita. Be to, tam pačiam uždaviniui galima sudaryti daug skirtingų programų. Todėl ne visada iš karto pavyksta sudaryti gražią, gero stiliaus programą.

Programavimas yra kūrybinis procesas, ir nėra bendrų receptų, kaip sudaryti kiekvieno uždavinio programą. Tačiau galima suformuoti bendras taisykles, kurios padėtų šį darbą paspartinti, jį geriau atlikti.

Didesnį uždavinį kurį visą iš karto išspręsti sunku. Dažnai pavyksta lengviau įveikti jį suskaidžius į dalis. Mažesnes dalis būna lengviau išspręsti. Išsprendę atskirai kiekvieną dalį ir visų dalių sprendimus sujungę į vieną, gauname viso, didelio, uždavinio sprendimą.

Ar galima suskaidyti į dalis didelio uždavinio programavimą?

Be abejo, galima. Tiktai darbas sklandžiau sektųsi, jeigu uždavinio dalis būtų galima programuoti atskirai, nepriklausomai vieną nuo kitos, o po lengvai, jų nepertvarkant, sujungti į vieną didelę programą. Tokios autonominės programų dalys yra funkcijos ir procedūros. Jos turi savus autonomiškus aprašus, savus pradinius duomenis ir rezultatus, per kuriuos palaiko ryšius su kitomis programos dalimis.

Skaityti programą, sudarytą iš funkcijų ir procedūrų, taip pat lengviau. Mat aiškiai matosi savarankiškų dalių ribos ir ryšiai tarp jų. Kiekvieną funkciją ir procedūrą galima nagrinėti atskirai.

Su funkcijomis ir procedūromis jau susidūrėme. Tai buvo standartinės Paskalio kalbos funkcijos (pvz., abs, sqrt, succ, pred) bei procedūros (pvz., read, write). Jas jau mokame ir panaudoti.

O dabar pateiksime pavyzdį, iš kurio matysime, kad mums reikalinga nauja, funkcija, kurios neturi Paskalis.

Pavyzdys. Pradiniai duomenys – du natūralieji skaičiai a ir b. Rezultatas apskaičiuojamas pagal formulę

ab – ba.

Formulė paprasta. Veiksmai taip pat paprasti. Kėlimo laipsniu operacijos Paskalio kalboje nėra. Tačiau kėlimo laipsniu programą jau esame nagrinėję (žr.4.4 skyr. 1 pavyzdį). Čia kelti laipsniu reikia du kartus, vadinasi, du kartus rašyti tokį pat ciklą tik su kitais kintamaisiais. Programa bus paprastesnė, jeigu kėlimo laipsniu veiksmus aprašysime funkcija.

Sudarome šitokią programos schemą:

program formulė;
  var a, b, c: integer;

 
begin
 
read(a, b);
  c := laipsnis(a, b) - laipsnis(b, a);
  write(c)
end.

Vardu laipsnis pavadinome kėlimo laipsniu funkciją. Jos aprašyti kol kas nemokame (apie tai – kitame skyrelyje). Todėl vietoj būsimo aprašo piešiame stačiakampį. Kai išmoksime sudaryti funkcijos aprašą, stačiakampį pakeisime tokiu aprašu.

Kai pradiniai duomenys perskaityti, reikia apskaičiuoti rezultatą. Tam naudojame funkciją laipsnis. Po vardo skliaustuose rašome funkcijos parametrus. Tai pradiniai duomenys funkcijos rezultatui gauti. Laikome, kad pirmasis parametras yra laipsnio pagrindas, o antrasis – laipsnio rodiklis. Dėl to, pirmą kartą kreipdamiesi į funkciją, rašome laipsnis(a, b), o antrą kartą – laipsnis(b, a). Šie du užrašai vadinami kreipiniais į funkciją. Kaskart kreipiantis apskaičiuojama funkcijos reikšmė, kuri, atlikus funkcijos veiksmus, atsiranda kreipinio vietoje.

6.2. Funkcijų aprašai

Funkcijos aprašas panašus į programą. Jis turi savą aprašų dalį ir veiksmų dalį.

1 pavyzdys. Aprašykime ankstesnio skyrelio funkciją laipsnis:

function laipsnis(p, n: integer): integer;
                                             { p – laipsnio pagrindas }
                                             { n – laipsnio rodiklis }
  var pn, i: integer;
begin
 
pn := 1;
  for i := 1 to n do
   
pn := pn*p;
  laipsnis := pn
end.

Pirmoji eilutė yra funkcijos antraštė. Žodis function pasako, kad vardu laipsnis pavadinta funkcija. Kaip ir kreipinyje, po funkcijos vardo skliaustuose rašomi parametrai. Apraše nurodomi dar ir jų tipai. Funkcija laipsnis turi du parametrus (laipsnio pagrindą ir laipsnio rodiklį). Abu parametrai yra sveikieji skaičiai. Jų vardai p ir n. Už skliaustų – dvitaškis, o po jų nurodomas funkcijos reikšmės (rezultato) tipas. Kėlimo laipsniu rezultatas yra sveikasis skaičius, todėl rašomas žodis integer.

Funkcijos antraštė panaši į kintamojo aprašą, tik vietoj žodžio var rašomas žodis function ir skliaustuose nurodomi parametrai. Be to funkcijos aprašas dar nurodo, kokius veiksmus reikia atlikti, kad būtų gauta funkcijos reikšmę. Tie veiksmai ir sudaro minėtą savarankišką programos dalį, turinčią savus kintamuosius ir jų aprašus, savus sakinius. Šita programos dalis vadinama funkcijos programa, visa kita – pagrindine programos dalimi.

Rezultatas (funkcijos reikšmė) priskiriamas funkcijos vardui. Šiame pavyzdyje tai užrašyta sakiniu

laipsnis := pn

Funkcijų aprašai eina po kintamųjų aprašų. Visos programoje vartojamos funkcijos turi būti aprašytos (žinoma, išskyrus standartines, kurių aprašyti nereikia).

2 pavyzdys. Funkciją laipsnis įtraukime į ankstesnio skyrelio programą ir išnagrinėkime, kaip ir kada atliekami jos veiksmai.

program formulė;
  var a, b, c: integer;
  function laipsnis(p, n: integer): integer;
                                               { p – laipsnio pagrindas }
                                               { n – laipsnio rodiklis }
    var pn, i: integer;
    begin
     
pn := 1;
      for i := 1 to n do
        
pn := pn*p;
      laipsnis := pn
    end;                         { funkcijos laipsnis aprašo pabaiga }
begin                           { čia prasideda pagrindinė programos dalis }
  read(a, b);
  c := laipsnis(a, b) - laipsnis(b, a);
  write(c)
end.

Funkcijos aprašo veiksmus kompiuteris tik įsimena, bet kol kas jų neatlieka. Veiksmai pradedami nuo pagrindinės programos dalies (žr. programą formulė), t. y. pirmasis sakinys, kurį atlieka kompiuteris, yra

read(a, b)

Funkcijos programos veiksmai atliekami tada, kai jų prireikia – kai, atliekant pagrindinę programos dalį, randamas kreipinys į funkciją. Programoje formulė tai įvyks, kai bus atliekamas antrasis pagrindinės programos dalies sakinys

c := laipsnis(a, b) - laipsnis(b, a)

Jo dešinėje pusėje yra du kreipiniai į funkciją laipsnis. Vadinasi, atliekant šį sakinį į funkciją bus kreipiamasi du kartus ir du kartus atliekami funkcijos aprašo veiksmai.

Kreipinyje užrašyti parametrai vadinami faktiniais, o funkcijos aprašo parametrai – formaliaisiais. Šiame pavyzdyje formalieji funkcijos laipsnis parametrai yra p ir n, o faktiniai parametrai kiekviename kreipinyje gali būti vis kitokie. Faktinių parametrų turi būti tiek pat, kiek ir formaliųjų. Prieš atliekant funkciją, formaliesiems parametrams priskiriamos faktinių parametrų reikšmės. Pirmajam formaliajam parametrui priskiriama pirmo faktinio parametro reikšmė, antram – antro ir t. t.

Faktiniai parametrai gali būti ne tik konstantos arba kintamieji, bet ir reiškiniai. Parametrus, kurie keičiami faktinių parametrų reikšmėmis, dar vadiname parametrais-reikšmėmis.

Grįžkime prie pavyzdžio. Vietoj kreipinio

laipsnis(a, b)

bus atliekami šitokie veiksmai:

1) visiems funkcijos laipsnis kintamiesiems ir jos programai paskiriama atmintis;
2) formaliesiems (funkcijos) parametrams priskiriamos faktinių (kreipinio) parametrų reikšmės:

p := a; n := b

Jeigu, pavyzdžiui, programos pradiniai duomenys būtų skaičiai 2 ir 5 (t. y. a = 2, b = 5), tai formalieji (funkcijos) parametrai įgytų tokias reikšmes:

p := 2; n := 5;

3) atliekama funkcijos programa, t. y. skaičius 2 pakeliamas laipsniu 5;
4) gautoji funkcijos reikšmė (laipsnis) įrašoma į programą vietoj kreipinio ir tęsiami programos pagrindinės dalies veiksmai, t. y. vėl kreipiamasi į funkciją laipsnis, tik jau su kitais parametrais (tiksliau – su tais pačiais parametrais, tik sukeistais vietomis).

26 paveiksle schemiškai parodyta, kaip atmintis paskirstoma kintamiesiems. Stačiakampiais pavaizduoti atminties laukai, skirti kintamųjų reikšmėms saugoti, o rodyklėmis – reikšmių persiuntimas iš vieno lauko į kitą. Stačiakampiuose surašytos tokios kintamųjų reikšmės, kurias jie įgyja, kai atliekamas kreipinys laipsnis(a, b), o parametrų reikšmės yra: a = 2 ir b = 5.


26 pav.

Tame pačiame prieskyros sakinyje antrąkart kreipiamasi į funkciją laipsnis su kitais parametrais. Dabar skaičius 5 bus keliamas kvadratu.

Po antro kreipinio apskaičiuojama reiškinio reikšmė: 32–25 = 7. Po to kitu sakiniu ji rašoma. Taigi šioje programoje funkcija laipsnis buvo panaudota du kartus. Tiek pat kartų buvo atlikti ir joje aprašyti veiksmai.

3 pavyzdys. Funkciją laipsnis įjunkime į kitą programą, pagal kurią randama skaičių nuo 1 iki 10 n-tųjų laipsnių suma (n – pradinis duomuo).

program suma;
   const iki = 10;             { iki kiek sumuojama }
   var n,                         { laipsnio rodiklis }
         s: integer;             { laipsnių suma }
          j: 1..iki;
   function laipsnis(p, n: integer): integer;
      var pn, i: integer;
   begin
     
pn := 1;
      for i := 1 to n do
        
pn := pn * p;
      laipsnis := pn
   end;
begin
  
read(n);
   s := 0;
   for j := 1 to iki do
     
s := s + laipsnis(j, n);
   writeln(s)
end.

Kreipinys į funkciją laipsnis yra cikle. Į ją bus kreipiamasi tiek kartų, kiek kartų atliekamas ciklas, t. y. 10 kartų.

Kadangi funkcijos aprašas yra savarankiška programos dalis, turinti savus kintamuosius, tai visi funkcijos viduje aprašyti kintamieji skiriasi nuo pagrindinėje programos dalyje aprašytų kintamųjų, netgi jei jie turi tuos pačius vardus. Šiame pavyzdyje vardu n buvo pavadintas programos pagrindinės dalies kintamasis ir funkcijos parametras. Tačiau tai skirtingi kintamieji. Kiekvienam jų priskiriama atskira vieta kompiuterio atmintinėje. Programos kintamųjų vardai nepainiojami, nes jų vartojimo sritys nesutampa. Pagrindinėje programos dalyje parašytas kintamasis n gali būti vartojamas bet kur programoje, išskyrus funkcijos laipsnis vidų, o funkcijoje aprašytas kintamasis n – tik funkcijoje.

Programuotojas, sudarydamas funkcijos aprašą (funkcijos programą), gali jos viduje parinkti vardus, neatsižvelgdamas į kitose programos dalyse vartotus vardus. Tai labai svarbi programavimo kalbos ypatybė: ji ypač praverčia sudarant dideles programas, kuriose būna daug vardų.

4 pavyzdys. Sudarysime funkciją didesniajam iš dviejų skaičių rasti. Programą šiam uždaviniui jau esame rašę. Dabar tuos pačius apiforminsime kaip funkcijos aprašą ir galėsime panaudoti bet kur programoje.

function max(a, b: integer): integer;
begin
  if
a > b then max := a
             else max := b
end;

Pritaikykime šią funkciją didžiausiai iš keturių kintamųjų a, b, c ir d reikšmei rasti.

didž := max(max(a, b), max(c, d))

Šiame sakinyje funkcija max vartojama tris kartus:

1) max(a, b) – didesniajai kintamųjų a ir b reikšmei rasti;
2) max(c, d) – didesniajai kintamųjų c ir d reikšmei rasti;
3) didžiausiai (iš rastų dviejų didesniųjų) reikšmei rasti.

5 pavyzdys. Jeigu dažnai reikia ieškoti didžiausio iš keturių skaičių, tai pravartu sudaryti šiam tikslui skirtą funkciją. Pavadinkime ją max4. Programos viduje vartosime jau žinomą funkciją max didesniajam iš keturių skaičių rasti. Sudarome šitokią programą:

program didelis;
   var a, b, c, d, e, f, g, h: integer;
   function max(a, b: integer): integer;
   begin
       if
a > b then max := a
                  else max := b
   end;
   function
max4(a, b, c, d: integer): integer;
   begin
      
max4 := max(max(a, b), max(c, d))
   end;
begin                     { čia prasideda pagrindinė programos dalis }
   read(a, b, c, d, e, f, g, h);
   writeln(max4(a, b, c, d));
   writeln(max4(e, f, g, h));
   writeln(max4(a+e, b+f, c+g, d+h));
   writeln(max4(a-e, b-f, c-g, d-h))
end.

Iš programos didelis pagrindinės dalies kreipiamasi į funkciją max4 keturis kartus. Kaskart iš funkcijos max4 į funkciją max kreipiamasi tris kartus. Vadinasi, iš viso funkcijos max4 veiksmai atliekami 4 kartus, o funkcijos max – 12 kartų.

Šiuo pavyzdžiu parodėme, kad į funkciją gali būti kreipiamasi ne tik pagrindinėje programos dalyje, bet ir kitoje funkcijoje (šiuo atveju – funkcijoje max4).

6 pavyzdys. Sudarysime loginę funkciją, kurios reikšmė yra true, jei duotieji metai keliamieji, ir false – priešingu atveju. Funkciją įjungsime į programą, nustatančią, kurie metai duotame intervale yra keliamieji.

program keliamieji;
   var pradžia, pabaiga, metai: integer;
   function kel(m: integer): boolean;
   begin
      if
m <= 1583 then kel := m mod 4 = 0
                          else kel := (m mod 400 = 0) or
                                          
(m mod 100 <> 0) and
                                          
(m mod 4 = 0)
   end;
begin
  
read(pradžia, pabaiga);
   for metai := pradžia to pabaiga do
      if
kel(metai) then writeln(metai, ' KELIAMIEJI')
                        else writeln(metai, ' PAPRASTIEJI')
end.

Uždaviniai

6.2.1. Duotos funkcijos max ir max4, aprašytos 5 pavyzdyje. Kurie kreipiniai netaisyklingi ir
         kodėl?

a) max(10, 25);
b) max(0, 0);
c) max(-10, -25);
d) max(10, 20, 30);
e) max(true, false);
f) max4(a, b, c);
g) max4(1, 2, 3, 4);
h) max4(d, c, b, a).

6.2.2. Sudarykite funkciją mažesniajam iš dviejų skaičių rasti.

6.2.3. Sudarykite funkciją skaičiaus faktorialui rasti.

6.2.4. Panaudodami funkciją max4, parašykite sakinį keturių duotųjų skaičių a, b, c ir d
         didžiausiam paskutiniam skaitmeniui rasti.

Pavyzdžiui, jeigu a = 25, b = 130, c = 127, d = 1985, tai rezultatas turi būti 7.

6.2.5. Sudarykite funkciją natūraliojo skaičiaus skaitmenų sumai rasti.

6.2.6. Sudarykite loginę funkciją, patikrinančią, ar trys duotieji skaičiai sudaro aritmetinę
         progresiją.

6.2.7. Dažnai spaudoje didesni skaičiai išreiškiami tūkstančiais. Pavyzdžiui, rašoma 124
         tūkst. litų
užuot rašius 124 000 litų. Parašykite funkciją kuri sveikąjį skaičių paverstų
         tūkstančių skaičiumi jį apvalindama iki sveikų tūkstančių.

6.3. Daugkartinis uždavinio skaidymas į dalis ir jų išreiškimas funkcijomis

Kai didelis uždavinys suskaidomas į dalis, gali pasirodyti, kad ir dalys dar per didelės, kad iš karto būtų galima parašyti jų programas. Tada skaidymas tęsiamas: didesnės dalys vėl skaidomos į mažesnes, iš jų didesnės vėl skaidomos ir t.t., kol nebelieka sunkiai įveikiamų dalių.

Skaidymą pademonstruosime su nelabai dideliu, bet gerai besiskaidančiu į dalis uždaviniu.

Datų uždavinys. Sudarykime programą dienų skaičiui tarp dviejų duotų datų rasti.

Pradiniai duomenys – dvi datos. Kiekviena jų išreiškiama trimis skaičiais: metais, mėnesiu ir diena. Abiejų datų metai ne ankstesni kaip 1583 (jau buvo įvestas Grigaliaus kalendorius). Reikia rasti dienų skaičių tarp tų datų. Jeigu antroji data yra ankstesnė už pirmąją, tai dienų skaičius turi būti neigiamas. Jeigu abi datos tos pačios – dienų skaičius tarp jų lygus nuliui.

Uždavinį suskaidysime į šitokias dalis:

1. Pradinių duomenų (dviejų datų) skaitymas;
2. Dienų skaičiaus tarp dviejų duotųjų datų radimas;
3. Rezultato (dienų skaičiaus) rašymas.

Pirmoji ir trečioji dalys yra pakankamai paprastos. Jas jau galima užrašyti konkrečiais sakiniais. Antroji dalis būtų paprasta, jeigu turėtume funkciją dienų skaičiui tarp dviejų datų rasti. Kol kas jos nėra. Funkciją sudarysime vėliau, o dabar programos eskize rašysime tik funkcijos antraštę, o visą kitą dalį vaizduosime stačiakampiu, kuriame žodžiais paaiškinsime, ko tikimės iš būsimos funkcijos.

program dienos;
   var mt1, mn1, dn1,                { pirmoji data }
         mt2, mn2, dn2,                { antroji data }
         d: integer;                        { dienų skaičius tarp datų }
   function dsk (mt1, mn1, dn1, mt2, mn2, dn2: integer): integer;

  

begin
  
read(mt1, mn1, dn1);
   read(mt2, mn2, dn2);
   d := dsk (mt1, mn1, dn1, mt2, mn2, dn2);
   write(mt1, '.', mn1: 2, '.', dn1: 2, ' ',
   mt2, '.', mn2: 2, '.', dn2: 2, d: 6)
end.

Duomenų skaitymą užrašėme dviem sakiniais, norėdami paryškinti, kad skaitomos dvi skirtingos datos. Į rašymo sakinį įtraukėme ne tik rezultatą, bet ir pradinius duomenis, kad matytųsi iš kurių buvo gautas rezultatas.

Svarbiausią uždavinio dalį – dienų skaičiaus radimą tarp dviejų datų – užrašėme funkcija dsk. Dabar ją programuokime.

Pradiniai funkcijos duomenys yra dvi datos, išreikštos šešiais skaičiais. Rezultatas – dienų skaičius tarp tų datų. Pasvarstykime, kaip galima rasti rezultatą.

Pirmas metodas

Uždavinį pavaizduokime grafiškai (kai mt1 = 1997, o mt2 = 2000).

 

Reikia rasti tris dienų skaičius:

d1 – nuo datos D1 iki metų mt1 pabaigos,
d2 – per visus metus (tarp metų mt1 pabaigos ir metų mt2 pradžios),
d3 – nuo metų mt2 pradžios iki datos D2.

Sudėję visus tris skaičius, gautume rezultatą:

dsk := d1 + d2 +d3.

Antras metodas

 

Reikia rasti du dienų skaičius:

d1 – nuo pradinės datos D0 (1583 m. sausio 1 d.) iki datos D1,
d2 – nuo pradinės datos D0 iki datos D2.

Gautų skaičių skirtumas būtų rezultatas:

dsk := d2 – d1.

Trečias metodas

 

Reikia rasti tris dienų skaičius:

d1 – nuo metų mt1 pradžios iki metų mt2 pradžios,
d2 – nuo metų mt1 pradžios iki datos D1,
d3 – nuo metų mt2 pradžios iki datos D2.

Rezultatą gautume pagal formulę

dsk := d1 – d2 + d3.

Kurį metodą pasirinkti?

Jeigu pasirinktume pirmąjį, tai reikėtų sudaryti tris skirtingas programos dalis skaičiams d1, d2 ir d3 rasti. Be to, šis metodas netinka, kai pirmoji data vėlesnė už antrąją. Jeigu pasirinktume antrąjį metodą, tai reikėtų rasti du skaičius – d1 ir d2. Juos abu galėtume rasti pagal tą pačią funkciją. Todėl antrasis metodas yra universalesnis ir paprastesnis. Tačiau reikia vartoti pradinę datą. Sprendžiant trečiuoju metodu, trims skaičiams rasti reikia dviejų skirtingų funkcijų (skaičius d2 ir d3 galima rasti pagal tą pačią funkciją).

Pasirenkame trečiąjį metodą, dienų skaičių tarp dviejų datų išreikšdami dviem funkcijomis:

function dsk (mt1, mn1, dn1, mt2, mn2, dn2: integer): integer;
    function dmt (mt1, mt2: integer): integer;

   

          function dmtpr (mt, mn, dn: integer): integer;

         

begin
 
dsk := dmt(mt1, mt2) - dmtpr(mt1, mn1, dn1)
                                 + dmtpr(mt2, mn2, dn2)
end;

Štai ir sudarėme funkciją dsk. Jos veiksmus išreiškėme kitomis dviem paprastesnėmis funkcijomis. Taigi funkciją dsk užbaigėme.Tačiau visa programa dar nebaigta – neaprašytos funkcijos dmt ir dmtpr. Toliau programuosime funkcijų dmt ir dmtpr vidų, o funkcijos dsk programos neliesime.

Dabar reikia programuoti kitas dvi funkcijas. Funkcijos dmt reikšmę galima rasti sudėjus visų metų, esančių duotame intervale, dienų skaičių. Kadangi dienų skaičius metuose priklauso nuo to, ar metai keliamieji, tai reikia naudoti ciklą, o jame – sąlyginį sakinį.

Čia dar reikia nepamiršti, kad antroji data gali būti vėlesnė už pirmąją. O tada, kaip reikalauja uždavinio sąlyga, rezultatas turi būti neigiamas.

function dmt (mt1, mt2: integer): integer;
  var m, { metai }
        d: integer; { dienos }
  function kel (m: integer): boolean;
 
  begin
    
d := 0;
     for m := mt1 to mt2 - 1 do
          if
kel (m) then d := d + 366
                        else d := d + 365;
     for m := mt2 to mt1 - 1 do
          if
kel(m) then d := d - 366
                       else d := d - 365;
     dmt := d
  end;

Funkciją, nustatančią, ar metai yra keliamieji, jau sudarėme 6.2. skyrelyje. Ją ir perrašome:

function kel (m: integer): boolean;
begin
    if
m < 1583
        then kel := m mod 4 = 0
        else kel := (m mod 400 = 0) or
                        
(m mod 100 <> 0) and
                        
(m mod 4 = 0)
end.

Ši funkcija yra universalesnė negu reikėtų mūsų programai: ji tinka metams ir ankstesniems už 1583. Šią funkciją galima būtų suprastinti: palikti tik antrąją sąlyginio sakinio šaką. Tačiau jos neprastinsime. Programuotojai, vartodami savo programose kitų sudarytas funkcijas, stengiasi jų nekeisti, kad nepadarytų klaidų.

Taigi turime užbaigtą vieną programos šaką. Liko dar kita šaka - rasti, kiek dienų prabėgo nuo metų mt pradžios iki mėnesio mn dienos dn.

Funkcijos reikšmę galima rasti, sudėjus visų mėnesių dienas nuo metų pradžios iki mėnesio mn pradžios, o prie gautos sumos pridėjus dn dienų. Kadangi mėnesiai turi nevienodą dienų skaičių, tai teks naudoti ciklą, o jame – sąlyginį sakinį. Be to, dienų skaičius vasario mėnesį priklauso nuo to, ar metai mt keliamieji. Vadinasi, ir čia bus reikalinga funkcija kel:

function dmtpr (mt, mn, dn: integer): integer;
  var mėn, d: integer;
  function kel (m: integer): boolean;
  ...
begin      { dmtpr }
  d := 0;
  for mėn := 1 to mn - 1 do
    case
mėn of
        
1, 3, 5, 7, 8, 10, 12: d := d + 31;
         4, 6, 9, 11 :             d := d + 30;
         2: if kel(mt) then     d := d + 29
                           else     d := d + 28
    end
end;

Surašę visas funkcijas, gauname šitokią programą:

program dienos;
   var mt1, mn1, dn1,                  { pirmoji data }
         mt2, mn2, dn2,                  { antroji data }
         d: integer;                         { dienų skaičius }

   function dsk (mt1, mn1, dn1, mt2, mn2, dn2: integer) : integer;
        function dmt (mt1, mt2: integer): integer;
        var m,                               { metai }
              d: integer;                    { dienos }
        function kel (m : integer): boolean;
        begin
            if
m < 1583 then kel := m mod 4 = 0
                              else kel := (m mod 400 = 0) or
                                              
(m mod 100 <> 0) and
                                              
(m mod 4 = 0)
        end;
   begin
{ dmt }
        d := 0;
        for m := mt1 to mt2-1 do
            if
kel(m) then d := d + 366
                         else d := d + 365;
        for m := mt2 to mt1 - 1 do
            if
kel(m) then d := d - 366
                         else d := d - 365;
        dmt := d
   end;

   function
dmtpr (mt, mn, dn: integer): integer;
       var mėn, d : integer;
       function kel (m : integer): boolean;
       begin
           if
m < 1583
              then kel := m mod 4 = 0
              else kel := (m mod 400 = 0) or
                              
(m mod 100 <> 0) and
                              
(m mod 4 = 0)
       end;

   begin { dmtpr }
       d := 0;
       for mėn := 1 to mn - 1 do
          case
mėn of
             
1, 3, 5, 7, 8, 10, 12: d := d + 31;
              4, 6, 9, 11:              d := d + 30;
              2: if kel(mt) then     d := d + 29
                                else     d := d + 28
          end;
      
dmtpr := d + dn
   end;

   begin
{ dsk }
       dsk := dmt(mt1, mt2) - dmtpr(mt1, mn1, dn1)
                                      + dmtpr(mt2, mn2, dn2)
   end;

begin
{ dienos }
   read(mt1, mn1, dn1);
   read(mt2, mn2, dn2);
   d := dsk (mt1, mn1, dn1, mt2, mn2, dn2);
   write(mt1, '.', mn1: 2, '.', dn1: 2, ' ',
   mt2, '.', mn2: 2, '.', dn2: 2, d: 6)
end.

Nors programą sudarėme iš kruopščiai patikrintų funkcijų, tačiau klaidų gali atsirasti jas jungiant. Galima suklysti arba ką nors praleisti ir perrašant. Todėl programą reikia išbandyti kompiuteriu. Tikrinimui, arba kaip dažnai sakome, programos derinimui, parenkami kuo įvairesni kontroliniai pradiniai duomenys, bet tokie, kurių rezultatą nesunku ir be kompiuterio apskaičiuoti. Keli tokie duomenys ir rezultatai, kurie turėtų būti gaunami pagal tokius duomenis, pateikti lentelėje.

Pirmoji data

Antroji data

Dienų skaičius tarp datų

1990 01 01

1991 01 01

  365

2000 01 01

2000 12 31

  365

1989 05 31

1989 06 24

    24

1900 02 25

1901 02 25

  365

1980 02 15

1990 02 15

3653

1980 03 15

1990 03 15

3652

1989 10 20

1988 10 20

 -365

1990 04 01

1990 04 01

      0

Kontroliniai pradiniai duomenys buvo tik teisingos datos. Tačiau, eksploatuojant programą, gali pasitaikyti ir neteisingų pradinių duomenų – neegzistuojančių datų, pavyzdžiui, 1999 m. vasario 29 d., arba datų, nepatenkančių į uždavinio formuluotės apibrėžtą intervalą (pavyzdžiui, 1400 m. sausio 1 d.). Todėl reikėtų patikrinti, ar pradiniai duomenys teisingi. Dažnai programuotojai pradinius duomenis tikrinančias programos dalis sudaro ir įjungia į programą vėliau, po to, kai programa sudaryta ir patikrinta su teisingais pradiniais duomenimis. Mes irgi taip padarysime, atlikdami 6.3.3 uždavinį.

Sudarydami šią programą, vienas funkcijas įterpėme į kitas. Kaip jos įeina viena į kitą, pavaizduota 27 paveiksle. Funkcijos, esančios kitose funkcijose panašiai kaip ten aprašyti kintamieji, nežinomos už jų ribų. Todėl, pavyzdžiui, funkcijų dmt ir dmtpr, naudotų funkcijoje dsk, negalima naudoti pagrindinėje programos dalyje. Dėl to turėjome funkcijos kel aprašą kartoti. Jeigu funkcija kel būtų aprašyta tik funkcijoje dmt, tai ji netiktų funkcijai dmtpr, ir atvirkščiai. Žinoma, du kartus aprašyti tą pačią funkciją neracionalu. Vieno aprašo pakaktų, jeigu jį iškeltume į funkciją dsk (28 pav.).


27 pav.                                 28 pav.                                 29 pav.

Jeigu visas funkcijas aprašytume pagrindinėje programoje (29 pav.), galėtume jas naudoti visur. Tačiau funkcijas įtraukus į kitas funkcijas, savarankiškesnės būna programos dalys. Pavyzdžiui, programos pradžioje pavartodami funkciją dsk, dar nežinojome, ar programuojant šią funkciją prireiks kitų funkcijų. Jų ir nereikėjo. Skaidant uždavinį, pagrindinė programos dalis nepasikeitė, neatsirado net naujų vardų. Naujos funkcijos atsispindėjo tik funkcijos dsk viduje. Taigi racionaliausia reikėtų laikyti 28 paveiksle parodytą programos struktūrą.

Uždaviniai

6.3.1. Duota funkcija

function dpr(mt, mn, dn: integer): integer;
   var mėn, d: integer;
   function kel(m: integer): boolean;
   begin
      
kel :=(m mod 400 = 0) or
              
(m mod 100 <> 0) and
              
(m mod 4 = 0)
   end;
begin { dpr}
   d := 0;
   for mėn := 1 to mn - 1 do
      if
(mėn = 2) and kel(mt) then d := d + 29
        else if (mėn = 2) and not kel(mt) then d := d + 28
           else if (mėn < 8) and (mėn mod 2 = 0)
              then d := d + 30
              else if (mėn > 8) and (mėn mod 2) <> 0
                 then d := d + 30
                 else d := d + 31;
   dpr := d + dn
end

 

Ar vienodos funkcijų dpr ir dmtpr reikšmės, kai parametrų reikšmės tos pačios?

6.3.2. Ką reikėtų pakeisti programoje dienos, kad ji tiktų visiems mūsų eros metams?

P a s t a b a: paskutinė Julijaus kalendoriaus data buvo 1582 m. spalio mėn. 4 d.; po jos ėjo pirmoji Grigaliaus kalendoriaus data – 1582 m. spalio 15 d.

6.3.3. Parašykite funkciją, patikrinančią, ar duota data nuo 1583 m. iki 3000 m. yra teisinga.

Praktikos darbas

6.3.1. Klasės mokinių gimimo datos. Sudarykite programą, kurios pradiniai duomenys būtų klasės mokinių gimimo datos, o rezultatas – visų jų pragyventų dienų bendras skaičius šiandien ir kiekvieną kitą dieną per mėnesį į priekį.

6.4. Procedūros

Funkcija gali turėti daug pradinių duomenų (parametrų) ir tik vieną rezultatą – funkcijos reikšmę. Tačiau dažnai patogu išskirti savarankiškas programos dalis, kurių rezultatai yra kelios reikšmės. Tuo tikslu vartojama kita kalbos konstrukcija – procedūra.

Išnagrinėkime pavyzdį. Pradiniai duomenys – du sveikieji skaičiai a ir b. Rezultatai – taip pat du sveikieji skaičiai x ir y. Pirmasis rezultatas x turi būti lygus mažesniam iš skaičių a ir b, antrasis – y – didesniam. Taigi reikia dviejų rezultatų, o jiems gauti – dviejų funkcijų, pavyzdžiui, min ir max, ir užrašyti šitokius sakinius:

x := min(a, b);
y := max(a, b)

Procedūrose ir pradiniai duomenys, ir rezultatai perduodami parametrais. Parametrų gali būti kiek reikia. Vadinasi, vartojant vieną procedūrą, galima gauti daug rezultatų.

1 pavyzdys. Sudarysime procedūrą minmax anksčiau minėtam uždaviniui spręsti ir įtrauksime ją į programą.

program procpvz;
   var a, b, c, d, x, y, z: integer;
   procedure minmax (aa, bb: integer;
      var xx, yy: integer);
      begin
         if
aa > bb
            then
               begin
xx := bb;
                         yy := aa
               end
            else
               begin
                     
xx := aa;
                      yy := bb
               end
   end;                     
{ procedūros minmax pabaiga }

begin                       { programos pradžia }
   minmax(3, 4, x, y);
   writeln(x, y);
   minmax(6, 5, x, y);
   writeln(x, y);
   read(a, b, c, d);
   minmax(a, b, x, y);
   writeln(x, y);
   minmax(c, d, x, z);
   writeln(x, z)
end.

Pirmoji procedūros aprašo eilutė – procedūros antraštė. Po žodžio procedure rašomas procedūros vardas, po jo skliaustuose išvardijami formalieji parametrai.

Procedūra minmax turi 4 parametrus: aa, bb, xx ir yy. Pirmieji du (aa, bb) yra pradiniai duomenys. Jie aprašomi taip, kaip ir funkcijų parametrai. Kreipiantis į procedūrą, tiems parametrams priskiriamos faktinių parametrų, nurodytų kreipinyje, reikšmės. Kiti du parametrai (xx ir yy) skirti procedūros rezultatams. Prieš juos rašomas žodis var, pabrėžiantis, kad kreipinyje į procedūrą šiuos parametrus atitinkantys faktiniai parametrai turi būti kintamieji (ne konstantos ir ne reiškiniai).

Po procedūros antrašte vienu sudėtiniu sakiniu užrašomi jos veiksmai (procedūros programa). Tose programos vietose, kur reikia atlikti procedūros veiksmus (procedūrą), rašomas kreipinys. Kiekvienas kreipinys į procedūrą yra atskiras sakinys. Toje programos vietoje, kur parašytas kreipinys, atliekama procedūros programa.

Programoje procpvz pirmasis kreipinys į procedūrą minmax yra

minmax(3, 4, x, y).

Vadinasi, šioje programos vietoje bus pirmą kartą atliekama procedūra minmax. Jos pradiniai duomenys yra skaičiai 3 ir 4. Rezultatai yra kintamųjų x ir y reikšmės.

Rezultatams skirti parametrai vadinami parametrais-kintamaisiais. Prieš juos procedūros antraštėje rašomas žodis var. Procedūroje minmax tokie parametrai yra xx ir yy. Jiems neskiriama vieta atmintyje, jų reikšmės saugomos ten, kur ir juos atitinkančių faktinių parametrų (kintamųjų) reikšmės (30 pav.). Vadinasi, tas pats atminties laukas, kuris buvo paskirtas kintamajam (faktiniam parametrui), kreipimosi į procedūrą momentu tarsi įgyja antrą vardą. Taigi procedūroje veiksmai faktiškai atliekami su kreipinyje įrašytais kintamaisiais.

   30 pav.

Grįžkime prie pavyzdžio. Kreipiniu

minmax(3, 4, x, y)

procedūros minmax parametrams aa ir bb bus priskirtos konstantų 3 ir 4 reikšmės (žr. 30 pav.). Atliekant procedūrą, kintamieji x ir y įgyja naujus vardus xx ir yy, parašytus procedūroje. Taigi visi veiksmai, kurie nurodyti procedūroje su kintamaisiais xx ir yy, bus faktiškai atliekami su kintamaisiais x ir y, parašytais kreipinyje ir esančiais pagrindinėje programos dalyje. Priskiriant arba kitaip keičiant šių kintamųjų reikšmes, rezultatas perduodamas iš procedūros į pagrindinę programos dalį.

Atlikus pirmąjį kreipinį į procedūrą minmax, kintamųjų x ir y reikšmės bus 3 ir 4. Kreipiantis į procedūrą antrą kartą (minmax(6, 5, x, y)), visi procedūros minmax veiksmai bus atliekami iš naujo ir gaunami rezultatai x = 5 ir y = 6. Kiti du kreipiniai atliekami su pradiniais duomenimis, kurių reikšmės rašant programą nežinomos.

Kai pradinių duomenų reikšmės a = 15, b = 14, c = 13 ir d = 12, kompiuteris pagal programą procpvz išspausdina šitokius rezultatus:

  3      4
  5      6
14    15
12    13

2 pavyzdys. Sudarysime procedūrą skaičių nuo 1 iki n kvadratų ir kubų sumai rasti.

procedure kvkub (n: integer; var kv, kub: integer);
   var k: integer;
begin
  
kv := 0; kub := 0;
   for k := 1 to n do
       begin
          
kv := kv + k*k;
           kub := kub + k*k*k
       end
end;

3 pavyzdys. Sudarysime procedūrą didžiausiam mx ir mažiausiam mn skaičiui iš trijų duotųjų skaičių a, b ir c rasti. Procedūroje vartosime 6.2. skyr. aprašytas funkcijas min ir max.

procedure xxx (a, b, c: integer; var mx, mn: integer);
begin
  
mx := max(max(a, b), c);
   mn := min(min(a, b), c)
end;

Uždaviniai

6.4.1. Duotas procedūros aprašas:

procedure p (a: integer; var x: integer);
begin x := 2*a end

Prieš kreipiantis į procedūrą, buvo atlikti tokie programos sakiniai:

a := 10; b:= 15

Nustatykite, kurie iš išvardytų kreipinių netaisyklingi ir kodėl. Jeigu kreipinys taisyklingas, nurodykite rezultatą, gautą atlikus procedūrą.

a) p(a);
b) p(5, a, b);
c) p(b, b);
d) p(a, b);
e) p(7, b);
f) p(a+1, b);
g) p(a, 12);
h) p(a, b+1);
i) p(25, a);
j) p(true, b).

6.4.2. Pradiniai duomenys – sveikieji teigiamai skaičiai m ir n (m < n). Užrašykite sakinius
         skaičių nuo m iki n kvadratų sumai x ir kubų sumai y rasti. Sumoms skaičiuoti
         vartokite procedūrą kvkub.

6.4.3. Pradiniai duomenys – trys skaičiai (a, b ir c), reiškiantys trikampio kraštinių ilgius,
         surašyti nemažėjančia eile (t. y. a <= b <= c). Sudarykite procedūrą, kurios du
         rezultatai (juos žymėkite stat ir lyg) būtų loginė reikšmė: 1) stat = true, jei trikampis
         statusis, ir stat = false – priešingu atveju; 2) lyg = true, jei trikampis lygiašonis, ir lyg
        
= false – priešingu atveju.

6.5. Pradinių duomenų ir rezultatų perdavimas tais pačiais parametrais

Jau sakėme, kad procedūros parametrų-kintamųjų reikšmės saugomos ten pat, kur ir juos atitinkančių procedūros kreipinyje faktinių parametrų-kintamųjų reikšmės. Jeigu, prieš kreipiantis į procedūrą, tokiems faktiniams parametrams jau buvo priskirtos reikšmės, tai jos procedūroje gali būti panaudotos kaip pradiniai duomenys.

1 pavyzdys. Sudarysime labai paprastą procedūrą jos parametro reikšmei padidinti vienetu. Procedūrą pavadinkime vardu padid ir įjungsime į programą pr.

program pr;
  var a: integer;
  procedure padid (var x: integer);
  begin
     
x := x + 1
  end;
begin
 
a := 5;
  padid(a);
  write(a);
  padid(a);
  writeln(a: 6)
end.

Procedūroje padid parametras x kartu yra ir pradinis duomuo, ir rezultatas. Nesunku įsitikinti, kad kompiuteris pagal tokią programą išspausdins šiuos rezultatus:

6        7

Pateikiame dar procedūrų pavyzdžių.

2 pavyzdys. Sudarysime procedūrą dviejų kintamųjų reikšmėms sukeisti vietomis ir ją įtrauksime į programą.

program tvarka;
   var x, y, z: integer;
   procedure keisti (var a, b: integer);
      var t: integer;
   begin
     
t := a;
      a := b;
      b := t
   end;
begin                      
{ programos pradžia }
   read(x, y, z);
   if x > y then keisti(x, y);
   if y > z then keisti(y, z);
                                  { sukeitus y ir z vietomis }
                                  { gali vėl tekti keisti vietomis x ir y }
   if x > y then keisti(x, y);
   writeln(x, y:5, z:5)
end.

Pagal šią programą gauti rezultatai bus tie patys pradiniai duomenys, parašyti nuo mažiausio iki didžiausio. Pavyzdžiui,

22    44    33

kompiuteris rašo

22    33    44

Tokie patys rezultatai būtų rašomi, jei pradiniai duomenys būtų šie:

44    33    22 arba
44    22    33 ir t. t.

3 pavyzdys. Sudarysime procedūrą duotajam natūraliajam skaičiui suapvalinti dešimčių tikslumu:

procedure apvalus (var x: integer);
begin
   
x := (x + 5) div 10 * 10
end;

Jeigu procedūros parametras yra byla, tai jis turi būti persiunčiamas kintamuoju. Mat bylos būsena keičiama visada, netgi tuo atveju, kai byla skaitoma: po kiekvieno skaitymo veiksmo pasikeičia žymeklio, rodančio skaitymo vietą, padėtis.

4 pavyzdys. Sudarysime procedūrą didžiausiam skaičiui byloje rasti.

procedure maksimumas (var skbyla: text; var maks: integer);
                                        { skbyla – skaičių byla }
                                        { maks – didžiausias skaičius byloje }
   var sk: integer;               { perskaitytas skaičius }
begin
  
reset(skbyla);
   maks := -maxint-1;          { tikrai nedidesnis už bet kurį skaičių }
                                        { dažniausiai mažiausias skaičius kompiuteryje }
                                        { yra vienetu mažesnis už -maxint }
   while not eof(skbyla) do
       begin
         
read(skbyla, sk);
          if sk > maks            { rastas skaičius, didesnis už maks }
             then maks := sk
       end
end;

Procedūroje nerašėme sakinio assign. Procedūra turi būti kuo mažiau priklausoma nuo įvairių detalių, tarp jų ir bylų diske.

Procedūra maksimumas duoda tik vieną rezultatą. Todėl algoritmą būtų galima išreikšti ir funkcija. Tačiau taip nedarėme dėl to, kad ši procedūra duoda ne tik pagrindinį rezultatą – randa didžiausią skaičių byloje, bet ir keičia bylos būseną: kai skaito skaičius keičia žymeklio, rodančio skaitomą duomenį, vietą. Procedūrai tokie veiksmai priimtini (iš jos galima tikėtis kelių rezultatų. Tuo tarpu iš funkcijos tikimasi tik vieno rezultato. Todėl geras programavimo stilius reikalauja, jog funkcija nekeistų jokių kintamųjų reikšmių, esančių už funkcijos ribų.

Sakoma, kad funkcijos, keičiančios kokių nors kintamųjų reikšmes už jų ribų, duoda šalutinį efektą. Apie šalutinį efektą galima paskaityti straipsnyje [8].

Išnagrinėję pateiktus pavyzdžius, galime aiškiai suvokti, kuo skiriasi parametrai-kintamieji (t. y. tie parametrai, prieš kuriuos procedūros antraštėje yra žodis var) nuo parametrų-reikšmių. Parametrais-kintamaisiais duomenis galima perduoti iš kreipinio į procedūrą ir atvirkščiai, t. y. perduoti pradinius duomenis procedūrai ir gauti rezultatus iš procedūros, o parametru-reikšme perduodami duomenys tik iš kreipinio į procedūrą. Taigi parametrai-kintamieji yra universalesni už parametrus-reikšmes. Tačiau tai nereiškia, kad visada galima naudoti vien parametrus-kintamuosius. Tais atvejais, kai parametrus perduodami vien pradiniai duomenys, patogiau naudoti parametrą-reikšmę dėl šių priežasčių:

1. Formalųjį parametrą-reikšmę atitinkantis faktinis parametras gali būti ne tik kintamasis, bet ir konstanta arba reiškinys.

2. Parametrų-reikšmių savybės yra tokios pat, kaip ir kitų procedūros programoje aprašytų kintamųjų, tiktai prieš procedūros veiksmus pradžioje jiems priskiriamos pradinės reikšmės – kreipinyje nurodytų faktinių parametrų (kintamųjų, konstantų, reiškinių) reikšmės. Niekas daugiau faktinių ir formaliųjų parametrų nesieja. Vadinasi, procedūra nepakeis kreipinyje parašytų kintamųjų reikšmių. Tai ypač svarbu, kai tą pačią procedūrą vartoja daug programuotojų.

Teoriškai ir funkcija gali turėti parametrų-kintamųjų. Tačiau, vartojant juos funkcijose, suprastėja programavimo stilius, nes funkcijos rezultatas turi būti vienas ir perduodamas funkcijos vardu.

Uždaviniai

6.5.1. Ką išspausdintų kompiuteris, atlikęs programą apvalus (žr. 3 pavyzdį), jeigu ciklo
         viduje esantį sakinį read(a) perkeltume į sudėtinio sakinio pradžią, o pradiniai
         duomenys būtų tie patys?

6.5.2. Duota procedūra:

procedure apv (var x: integer; y: integer);
   var p, n: integer;
begin
  
n := 1;
   for p := 1 to y do
      
n := n * 10;
   x := (x + 5 * (n div 10)) div n * n
end;

Paaiškinkite, kokį veiksmą ši procedūra atlieka ir kaip jis pakeistų kintamojo p reikšmę, atlikus kreipinį

apv(p, 2)
jeigu prieš tai kintamojo p reikšmė buvo šitokia:

a) 1988;
b) 49;
c) 1500.

6.5.3. Sudarykite procedūrą duotajam skaičiui pakelti nurodytu laipsniu.

6.5.4. Laikrodis rodo laiką, kurį išreiškia trijų kintamųjų reikšmės: valandos (12-os valandų
         skalėje), minutės ir sekundės. Sudarykite programą, kuri pakeistų kintamųjų
         reikšmes taip, kad jos reikštų laiką po sekundės.

6.5.5. Duota programa:

program parametrai;
   var a, b, c: integer;
   procedure p (x, y: integer; var z: integer);
   begin
      
x := 2; y := 2; z := 2;
       writeln(x, y: 5, z: 5)
   end;
   procedure
r (var x, y: integer; z: integer);
   begin
      
x := 3; y := 3; z := 3
   end;
begin
  
a := 1; b := 1; c := 1;
   p(a, b, c);
   writeln(a, b: 5, c: 5);
   r(a, b, c);
   writeln(a, b: 5, c: 5)
end.

Ką išspausdins kompiuteris, atlikęs šią programą?

6.6. Algoritmų užrašymas funkcijomis ir procedūromis

Į funkcijas ir procedūras žiūrėjome kaip į programavimo konstrukcijas, palengvinančias programos skirstymą į dalis. Tačiau tai ne vienintelė funkcijų ir procedūrų paskirtis. Jos dažnai vartojamos algoritmams užrašyti. Iki šiol algoritmą tapatinome su programą ir laikėme, kad programa – tai algoritmo užrašas, artimesnis kompiuteriui. Tačiau algoritmą taip pat sėkmingai galima užrašyti ir funkcija arba procedūra. Kiekviena šių konstrukcijų turi priemones pradiniams duomenims, rezultatams, vidiniams duomenims ir veiksmams su jais aprašyti – viską, ko reikia algoritmui.

Koks skirtumas tarp programos ir funkcijos bei procedūros algoritmų užrašymo požiūriu?

Programa su išoriniu pasauliu bendrauja skaitymo ir rašymo veiksmais. Funkcija ir procedūra su išoriniu pasauliu pasikeičia informacija per parametrus. Kai kalbame apie algoritmą, pirmiausia apibrėžiame pradinius duomenis ir rezultatus. Taigi, funkcijos ir procedūros netgi artimesnės algoritmams, negu programos: čia, kaip ir algoritme, tik išvardijami pradiniai duomenys bei rezultatai ir nesirūpinama jų skaitymu bei rašymu. Dėl to algoritmus įprasta užrašyti funkcijomis ir procedūromis.

Transliatoriui (o tuo pačiu ir kompiuteriui) galima pateikti tik programą. Tad ką daryti su algoritmu, kuris apipavidalintas kaip funkcija arba procedūrą?

Tokį algoritmą galima pateikti kompiuteriui, jį įdėjus į gaubiančią programą. Ar tai nepatogumas?

Iš dalies taip. Tačiau šį nepatogumą kompensuoja galimybė funkcijomis ir procedūromis abstrakčiau aprašyti algoritmą, nesigilinant, kaip pateikiami pradiniai duomenys ir kaip apipavidalinami rezultatai.

Algoritmą, užrašytą funkcija arba procedūra, kur kas lengviau įjungti į bet kurią programą, negu algoritmą, užrašytą programa. Šioje knygoje vis dažniau algoritminius uždavinių sprendimus užrašysime funkcijomis ir procedūromis.

Dauguma šioje knygoje pateiktų programų sprendė tokius paprastus uždavinius, kad jų programos neturėjo praktinės vertės. Argi verta rašyti programą dviejų skaičių aritmetiniam vidurkiui rasti arba didesniajam iš dviejų skaičių rasti. Tuo tarpu apipavidalinus kad ir labai mažą uždavinėlį funkcija arba procedūra, ją galima labai paprastai panaudoti daugelyje programos vietų ir daugelyje programų. Akivaizdūs tokių labai paprastų ir dažnai praktiškai vartojamų funkcijų pavyzdžiai gali būti standartinės funkcijos abs ir sqr. Juk paprasčiau parašyti

a := abs(b),

negu

if b < 0 then a := -b
           else a := b.

Jeigu algoritmo rezultatas yra viena (paprastoji) reikšmė, tai tokį algoritmą rekomenduojame išreikšti funkcija. Funkciją dažnai patogiau panaudoti programoje, negu procedūrą, kadangi kreipinys į funkciją yra reiškinys ir jį galima rašyti visur ten, kur galima panaudoti reikšmę tiesiogiai, be tarpinio kintamojo rezultatui perduoti.

Uždaviniai

6.6.1. Aritmetinio vidurkio skaičiavimo programą (žr. 1.1 skyr.) apipavidalinkite funkcija.

6.6.2. Palūkanų skaičiavimo programą (žr. 1.4 skyr.) apipavidalinkite funkcija. Dialogo
         veiksmų funkcijoje nenaudokite.

6.6.3. Palūkanų skaičiavimo programą apipavidalinkite procedūra. Rezultatai – du sveikieji
         skaičiai – litai ir centai.

6.6.4. Parašykite funkciją, kuri patikrintų, ar iš keturių atkarpų, kurių ilgiai duoti, galima
         sudaryti kvadratą arba stačiakampį. Aprašykite funkcijos duomenų tipą.
         Pasinaudokite 4.1.3 uždaviniu ir jo atsakymu.

E Ankstesnis puslapis

3 Turinys

Kitas puslapis F

tus0.gif (69 bytes)