|
ELEKTRONINĖS KNYGOS |
|
|
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ė: 3225 = 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:
d 1 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:
d 1 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:
d 1 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 |
|
|
|
|