ELEKTRONINĖS KNYGOS |
|
|
Gintautas GRIGAS
PROGRAMAVIMAS PASKALIU
|
5. PROGRAMAVIMO TECHNOLOGIJOS ELEMENTAI
|
Jau įpusėjome knygą. Jau sudarėme
keliolikos paprastų uždavinių programas ir matėme, kad kiekviena
jų yra savita. Dažnai ne iš karto pavyksta sudaryti gerą programą,
tokią, kad ją galima būtų laikyti tobulybės viršūne. Taigi,
atėjo laikas pamąstyti, kaip rašome programas, paieškoti būdų,
kaip programuoti greitai ir gerai.
Tam pačiam uždaviniui galima sudaryti daug
skirtingų programų. Programavimas yra kūrybinis procesas, ir
sunku rasti bendrus receptus, kaip sudaryti kiekvieno uždavinio
programą. Tačiau galima suformuoti bendras taisykles, kurios padėtų
šį darbą paspartinti, jį geriau atlikti. Tai ypač svarbu
sudarant didesnių uždavinių programas. Bet kokį didesnį darbą
lengviau įveikti, suskirsčius jį į dalis mažesnius darbus.
Tas pats tinka ir programavimui.
Uždavinio programavimą galima suskirstyti į
šitokias dalis etapus:
1) uždavinio formulavimas;
2) sprendimo metodo parinkimas ar sudarymas;
3) programos rašymas;
4) programos tikrinimas;
5) programos tobulinimas;
6) programos derinimas (išbandymas kompiuteriu).
Programa yra produktas, daiktas, kuriuo
naudosis daugelis žmonių. Mus supa daugybė žmogaus sukurtų
daiktų. Juos vertiname dėl to, kad jie atlieka jiems skirtas
funkcijas. Jais gėrimės, jeigu jie gražūs ir juose matome juos
sukūrusių žmonių mintį ir pagarbą mums, t.y., tiems, kas tais
daiktais naudojasi. Deja gražių daiktų ne tiek daug, o netikusių
mėtosi visur.
Programavimas yra ir mokslas ir menas. Šie
du požiūriai puikiai papildo vienas kitą. Aš jaučiu, kad
programavimas panašus į poeziją arba muziką. Yra elegantiškų
programų, yra grakščių programų, yra spindinčių programų. Aš
teigiu, kad galima parašyti puikias programas, kilnias programas ir
išties didingas programas (Donaldas Knutas).
|
5.1. Uždavinio formulavimas
|
Norint išspręsti bet kokį uždavinį, reikia
turėti jo sąlygą. Programavimo uždavinio sąlyga vadinama uždavinio
formuluote. Programavimo uždavinio sprendinys (rezultatas) yra
programa. Taigi, norint sudaryti programą, reikia turėti užduotį
programavimui uždavinio formuluotę.
Formuluojant uždavinį, reikia nuodugniai išsiaiškinti,
kokie reikalavimai keliami būsimai programai. Priešingu atveju
galima ko nors nenumatyti ir neatlikti veiksmų, kurie galbūt buvo
turimi galvoje, bet nebuvo aiškiai suformuluoti. Uždavinio
formuluotėje reikia aiškiai nurodyti, kokie turi būti pradiniai
duomenys, ką atlikti pagal programą ir kokių rezultatų norima.
(Kaip gauti rezultatus, t. y. kokius veiksmus atlikti, nustatoma vėliau,
kai sudaroma programa).
1 pavyzdys. Tarkime, kad gavome užduotį:
Reikia sudaryti programą duotųjų skaičių
sumai rasti.
Turime patikslinti, kiek yra duota skaičių,
arba (jeigu nežinoma, kiek jų yra) apibrėžti, kaip bus nustatoma
tų skaičių sekos pabaiga. Pateikiame kelias šio uždavinio
formuluotes.
1. Pradiniai duomenys du sveikieji skaičiai.
Reikia juos perskaityti ir išspausdinti, apskaičiuote ir išspausdinti
jų sumą.
2. Pradiniai duomenys dešimt sveikųjų
skaičių. Reikia juos perskaityti, apskaičiuoti ir išspausdinti jų
sumą.
3. Pradiniai duomenys sveikųjų skaičių,
nelygių nuliui, seka. Sekos pabaigoje nulis. Reikia perskaityti
pradinius duomenis, rasti ir išspausdinti jų sumą.
Kuris šių variantų geriausias, turi nuspręsti
būsimasis programos naudotojas, nes jis geriausiai žino savo uždavinį.
Kai programos naudotojas yra kartu ir programuotojas (o taip būna
mokantis programavimo), jis pats turi nuspręsti , kuris variantas
tinkamiausias.
2 pavyzdys. Pradinis duomuo yra skaičius,
reiškiantis metus. Reikia sudaryti programą, pagal kurią galima būtų
nustatyti, ar metai yra keliamieji.
Ar tai, kas pasakyta, galima laikyti tikslia uždavinio
formuluote. Be abejo, ne.
Pirma, nenurodyta, apie kokius metus kalbama:
šio šimtmečio, šio tūkstantmečio, ar bet kuriuos metus po
Kristaus gimimo. O gal tai ir metai prieš Kristų?
Antra, nepasakyta, kokia forma kompiuteris turi
pateikti rezultatą.
Patiksliname uždavinio formuluotę:
Pradinis duomuo yra natūralusis skaičius, reiškiantis
mūsų eros metus. Reikia sudaryti programą, pagal kurią
kompiuteris išspausdintų duotuosius metus ir žodį METAI, o po to
žodį KELIAMIEJI, jeigu metai keliamieji, arba žodį
PAPRASTIEJI, jeigu metai paprastieji, arba žodį NETEISINGI, jeigu
pradinis duomuo neteisingas.
Tokia uždavinio formuluotė jau pakankamai aiški
ir tiksli.
3 pavyzdys. Reikia parašyti programą,
kuri patikrintų, ar iš trijų atkarpų, kurių ilgiai duoti,
galima sudaryti trikampį. Reikia spausdinti duotuosius atkarpų
ilgius ir žodį TAIP, jei galima, arba NE, jei negalima sudaryti
trikampio.Išanalizuokime šią formuluotę.
Apie nulinius ir neigiamus atkarpų ilgius
neverta ir kalbėti, nes iš tokių atkarpų trikampio sudaryti
negalima. Todėl savaime aiškus atsakymas NE.
Iš pradžių galima pasigesti atkarpų ilgio
matavimo vienetų. Bet, gerai pagalvojus, pasidaro aišku, kad jų
nurodyti ir nereikia. Svarbu, kad visos atkarpos būtų išmatuotos
tais pačiais ilgio vienetais.
Taigi prie šios uždavinio formuluotės nieko
pridurti nereikia.
Uždaviniai
5.1.1. Duotos dvi uždavinio formuluotės:
1) Pradinis duomuo sveikasis skaičius
n. Reikia sudaryti programą visų intervalo (0; n) lyginių skaičių
sumai rasti.
2) Pradinis duomuo sveikasis skaičius
n. Reikia sudaryti programą visų lyginių skaičių nuo 0 iki n
(jei n nelyginis, tai iki n 1) sumai rasti. Jeigu n < 0,
tai sumuoti neigiamus skaičius. Jų suma neigiama.
Ar šios formuluotės ekvivalenčios, t. y.
ar galima sudaryti programą, atitinkančią abi formuluotes?
5.1.2. Uždavinio šitokia formuluotė.
Pradiniai duomenys šimto sveikųjų skaičių
seka. Sudarykite programą, kuri patikrintų, ar duotoje skaičių
sekoje yra bent vienas nulis.
Ko šioje formuluotėje trūksta?
|
5.2. Kaip kuriamas arba pasirenkamas uždavinio
sprendimo metodas
|
Programuotojas turi mokėti išspręsti uždavinį.
Tik po to, kai bus sudaryta programa, kompiuteris ją galės atlikti
ir išvaduoti žmogų nuo daugelio ilgų duomenų apdorojimo veiksmų.Tačiau
juos žmogus turi gerai mokėti atlikti ir sugebėti užrašyti
programoje. Taigi programuotojui visų pirma reikia išsiaiškinti,
kaip sprendžiamas uždavinys.
Daugelio paprastų uždavinių sprendimo būdas
akivaizdus. Pavyzdžiui, jeigu reikia atlikti aritmetinius veiksmus
su keletu skaičių, pakanka parašyti aritmetinį reiškinį; o
atliekant vienodus veiksmus su daugeliu skaičių, rašomas ciklas,
ir pan.
Programuojant sudėtingesnius uždavinius,
reikia remtis žinomais matematikos dėsniais, taisyklėmis,
teoremomis.
1 pavyzdys. Reikia rasti visų nelyginių
natūraliųjų skaičių, ne didesnių už n, sumą. Paprasčiausias
šio uždavinio sprendimo būdas parašyti ciklą, pagal kurį būtų
sumuojami visi iš eilės einantys nelyginiai skaičiai: 1 + 3 + 5
... . Tačiau neskubėkime. Ši seka aritmetinė progresija. O
progresijos narių sumą sn apskaičiuojame pagal
formulę:
sn = n×(a1
+ an )/2
čia a1 pirmas narys,
an paskutinis narys,
n narių skaičius.
Parašę šią formulę vietoj ciklo, daug kartų
sumažinsime kompiuterio darbą.
2 pavyzdys. Grįžkime prie ankstesnio
skyrelio 3 pavyzdžio uždavinio. Čia reikia patikrinti, ar iš
trijų atkarpų, kurių ilgiai duoti, galima sudaryti trikampį.
Norint išspręsti šį uždavinį, pakanka žinoti trikampio savybę,
teigiančią, kad kiekviena trikampio kraštinė yra mažesnė už
kitų dviejų kraštinių sumą.Pažymėję atkarpų ilgius raidėmis
a, b ir c, galime šią savybę išreikšti
loginiu reiškiniu
(a+b > c) and
(a+c > b) and (b+c
> a),
kurio reikšmė yra true, jeigu iš
atkarpų galima sudaryti trikampį, ir false priešingu
atveju.
3 pavyzdys. Reikia sudaryti programą,
kurį nustatytų į kokį pirminių daugiklių skaičių išskaidomas
duoto skaičiaus faktorialas. Pavyzdžiui, jeigu pradinis duomuo yra
skaičius 5, tai rezultatas turi būti 15, nes
10! = 3628800 = 2×2×2×2×2×2×2×2×3×3×3×3×5×5×7.
Paprasčiausias sprendimo būdas rasti skaičiaus
faktorialą, o po to jį skaidyti į pirminius daugiklius ir suskaičiuoti
tų daugiklių skaičių. Tačiau ir nedidelio skaičiaus
faktorialas yra labai didelis skaičius. Todėl greitai gausime
perpildymą. Betgi kai ir pradinis duomuo, ir rezultatas yra
nedideli skaičiai, nelogiška, kad būtų perpildymas. Todėl
reikia paieškoti kitokių sprendimo būdų.
Skaičiaus n faktorialas yra skaičių
nuo 1 iki n sandauga. Taigi galima skaidyti į pirminius
daugiklius atskirus skaičius jų nesudauginus.
Sprendžiant uždavinį, visada reikia
nuodugniai išanalizuoti jo formuluotę, neužmiršti visų galimų
atvejų, visų galimų pradinių duomenų reikšmių. Kartais sprendžiant
uždavinį aptinkama, kad formuluotėje ne viskas pasakyta arba joje
yra prieštaravimų. Tada ji tikslinama.
Daugelį uždavinių galima išreikšti
lygtimis. Programuotojas, be abejo, turi pats mokėti tas lygtis spręsti
ir jų sprendimo algoritmą pateikti programoje. Atskira matematikos
šaka (skaičiavimo matematika ir skaičiavimo metodai) nagrinėja
matematikos uždavinių, daugiausia lygčių, sprendimo metodus,
tinkančius programavimui.
Iš kelių uždavinio sprendimo metodų
pasirenkamas vienas, atsižvelgiant į jo universalumą,
programavimo paprastumą, kompiuterio laiko ir atminties ekonomiją
bei kitas charakteristikas, turinčias įtakos programavimui ir
programos atlikimui.
Tenka programuoti įvairių žmogaus veiklos
sričių (fizikos, biologijos, muzikos, ekonomikos ir pan.) uždavinius
ir atlikti veiksmus su jiems būdingais objektais (gyvūnais,
muzikos garsais, ekonominiais rodikliais ir pan.). Uždavinių
sprendimo metodus nagrinėja matematika, o veiksmai atliekami su
matematiniais objektais: skaičiais, loginėmis reikšmėmis ir
pan.Todėl nematematiniai uždaviniai pakeičiami jiems ekvivalenčiais
matematikos uždaviniais, kitaip sakant, sudaromas realaus pasaulio
uždavinio matematinis modelis. Toks keitimas vadinamas modeliavimu.
Su realaus pasaulio matematiniu modeliu susidūrėme,
nagrinėdami 3.1 skyrelio 1 pavyzdį. Tenai tiltus pakeitėme
loginiais kintamaisiais ir atlikome su jų reikšmėmis logines
operacijas, atspindinčias realų pasaulį.
|
5.3. Programos rašymas
|
Kai uždavinys nesudėtingas ir iš karto aišku,
kaip jį spręsti, tai nesunku ir jo programą parašyti. Sudėtingesnį
uždavinį aprėpti ir programuoti visą iš karto sunku, o labai
sudėtingą išvis neįmanoma. Todėl stambesnis uždavinys
skaidomas į smulkesnes dalis ir mėginama rašyti kiekvienos dalies
programą. Jeigu kuri nors dalis yra dar per stambi, ji skaidoma į
smulkesnes dalis tol, kol tos jų programos pasidaro pakankamai
trumpos ir vaizdžios. Šitaip dalimis galima parašyti ir labai
stambių uždavinių programas.
Pavyzdys. Parašykime programą 5.2
skyrelio 3 pavyzdžio uždaviniui: į kokį pirminių daugiklių
skaičių išskaidomas duoto skaičiaus faktorialas.
Pirmiausia sudarome programos eskizą,
program p;
var
n,
{ n! }
k,
{ faktorialo daugiklis }
d,
{vieno k pirminių daugiklių skaičius }
daugsk: integer;
begin
read(n);
daugsk := 0;
for k := 2 to n do
begin
daugsk
:= daugsk + d
end;
writeln(daugsk)
end.
Tuos veiksmus, kuriuos mokame programuoti, užrašėme
Paskalio kalbos žymenimis, o tuos , kurių dar neprogramavome,
pavaizdavome stačiakampiu su jame įrašytu žodiniu veiksmų
formulavimu. Taigi, suprogramavome tik dalį uždavinio. Tai, kas įrašyta
į stačiakampį, dar reikės programuoti. Taigi, programos rašymą
suskaidėme į dalis.
Dabar reikia suprogramuoti, t.y., užrašyti
Paskalio kalbos žymenimis stačiakampio veiksmus. Juos galima
paimti iš 4.5.2 uždavinio sprendimo ir pritaikyti šio uždavinio
programai.
program p;
var n,
nn,
{ n! }
k,
kk,
{ faktorialo daugiklis }
d,
{ vieno k pirminių daugiklių skaičius }
daugsk: integer;
begin
read(n);
daugsk := 0;
nn := n;
for k := 2 to n do
begin
kk := k;
d := 0;
while kk <=
nn do
begin
while nn mod kk = 0 do
begin
d := d + 1;
nn := nn div kk
end;
kk := kk + 1
end;
daugsk :=
daugsk + d
end;
writeln(daugsk)
end.
Štai ir visa programa. Perrašydami programos
fragmentą iš 4.5.2 uždavinio sprendimo, juose turėjome kai ką
pakeisti, ypač kintamųjų vardus. Teko programą papildyti naujų
kintamųjų aprašais. Tai nepatogu ir keičiant galima padaryti
klaidų. Šių nepatogumų galima išvengti naudojantis autonominėmis
programų dalimis funkcijomis ir procedūromis. Apie jas kalbėsime
6 skyriuje.
|
5.4. Programos tikrinimas ir derinimas
|
Jau spėjome patirti, kad, sudarant programą,
suklysti labai lengva. Todėl ją reikia kruopščiai ir nuodugniai
patikrinti dar prieš pateikiant kompiuteriui.
Tikrinant kiekvieną programą, rekomenduojama
įsitikinti, ar:
1) nėra sintaksės klaidų;
2) aprašyti visi (kintamųjų) vardai;
3) apibrėžiamos visų kintamųjų reikšmės prieš jas
vartojant;
4) programos veiksmai baigtiniai;
5) teisingi rezultatai.
Sintaksės (arba gramatikos) klaidos atsiranda,
kai, rašydami programą, nusižengiame programavimo kalbos (mūsų
atveju Paskalio) gramatikai pavartojame ne tuos arba ne ten,
kur reikia, skyrybos ženklus, netaisyklingai parašome kokią nors
kalbos konstrukciją ir pan. Sintaksės klaidos didesnių problemų
nekelia nes jas atranda kompiliatorius ir čia pat informuoja apie
jas.
Beveik visi kompiliatoriai neaptinka neapibrėžtų
reikšmių vartojimo. Primename, kad visuose reiškiniuose
(prieskyros sakinio dešinėje pusėje, po žodžių if, while,
to, rašymo sakiniuose ir kitur) galima vartoti tik apibrėžtas
(prieš tai priskirtas) kintamųjų reikšmes. Kai programą sudaro
vien paprastieji (prieskyros, duomenų skaitymo arba rašymo)
sakiniai, reikšmių apibrėžtumą patikrinti labai paprasta: prieš
kiekvieną sakinį, kuriame vartojama kintamojo reikšmė, bet
kurioje programos vietoje turi būti sakinys, suteikiantis reikšmę
tam kintamajam.
Kai kintamajam priskiriantis reikšmę sakinys
yra sąlyginiame sakinyje arba cikle, tai juo pasitikėti ne visada
galima. Mat toks sakinys gali būti kartais neatliekamas, o tada
kintamojo reikšmė gali likti neapibrėžta.
1 pavyzdys. Turime programą skaičiaus
absoliutiniam didumui (moduliui) rasti:
program abs;
var a, b : integer;
begin
read(a);
if a > 0 then b := a
else if a < 0 then b := -a;
writeln(b)
end.
Kai a = 0, neatliekama nė viena sąlyginio
sakinio šaka ir kintamojo b reikšmė lieka neapibrėžta.
Vadinasi, ši programa neteisinga vien dėl to, kad jos rezultatas
yra neapibrėžtas tik su viena pradinio duomens reikšme.
Jeigu kintamojo reikšmė apibrėžiama tik sąlyginiame
sakinyje, tai reikia įsitikinti, ar, esant bet kokiems pradiniams
duomenims, bus atliekama bent viena sakinio šaka, kurioje yra apibrėžiantis
reikšmę sakinys.
Jeigu kintamasis gauna reikšmę tik cikle, tai
reikia įsitikinti, ar tas ciklas visada bus bent kartą atliekamas.
Kompiuteris gali atlikti tik tokią programą,
kurioje reikalaujama baigtinio veiksmų skaičiaus. Kai programoje
yra ciklų, kurių antraštė prasideda žodžiu while, tai
atsiranda pavojus ciklui niekada nesibaigti.
Tam, kad ciklas būtų baigtinis, būtina (bet
nepakankama) sąlyga, jog ciklo viduje būtų keičiama bent viena
reikšmė, esanti ciklo antraštės sąlygoje. Pavyzdžiui, net ir
nesigilindami į atliekamų veiksmų prasmę, galime pasakyti, kad
nebaigtinis yra ciklas
while a > 0 do
write(a)
Jeigu ciklo antraštės sąlyga a > 0
yra tenkinama prieš atliekant ciklą, tai ji bus ir toliau
tenkinama, nes cikle nekeičiama kintamojo a reikšmė.
Kad minėta sąlyga yra tik būtina, bet
nepakankama, matyti iš šitokio pavyzdžio:
while a > 0 do
a := a + 1
Čia ciklo antraštės sąlygos kintamojo a
reikšmė keičiama didėjimo kryptimi. Jeigu sąlyga a >
0 buvo tenkinama prieš atliekant ciklą pirmą kartą, ji bus
tenkinama ir atlikus ciklą kiek norima kartų.
Išnagrinėkime kitą ciklą:
while a >= 0 do
a := a - 1
Šis ciklas yra baigtinis, kad ir kokia didelė
būtų kintamojo a reikšmė prieš atliekant ciklą: atiminėjant
iš šios reikšmės vienetą, ji vis tiek kada nors pasidarys
neigiama, sąlyga ciklo antraštėje nebus tenkinama ir ciklas
baigsis.
Kaip patikrinti, ar programos rezultatai
teisingi?
Pats paprasčiausias būdas išbandyti
kompiuteriu. Labai svarbu parinkti tinkamus kontrolinius pradinius
duomenis. Jeigu programoje yra ciklų, pravartu kontrolinius
duomenis parinkti tokius, kad ciklas nebūtų nė karto atliekamas,
kad būtų atliekamas vieną kartą ir kad būtų atliekamas kelis
kartus. Kai programoje yra sąlyginių sakinių, reikia parinkti
tokius kontrolinius duomenis, kad bent vieną kartą būtų atlikta
kiekvieno sąlyginio sakinio dalis (šaka).
2 pavyzdys. Tarkime, turime programą
skaičiui 2 pakelti laipsniu n:
program laipsnis;
var n,
{ laipsnio rodiklis }
p,
{ rezultatas }
k: integer;
begin
read(n);
p := 1;
for k := 1 to n do
p := p*2;
writeln(p)
end.
Jai patikrinti parenkame keletą pradinių
duomenų ir pateikę juos kompiuteriui gauname tokius rezultatus:
-5 1
0 1
1 2
2 4
5 32
Rezultatai teisingi, kai n >=0. Kai n
< 0, tai visada gauname vienetą. Todėl galima tvirtinti, kad ši
programa tinka dvejetui kelti teigiamu laipsniu.
Ar galima teigti, kad programos rezultatai yra
teisingi, esant bet kurioms pradinių duomenų reikšmėms, jei jie
teisingi su keliomis pasirinktomis pradinių duomenų reikšmėmis?
Deja, ne. Išnagrinėkime dar vieną pavyzdį.
3 pavyzdys. Tarkime, yra sudaryta kita
programa skaičiui 2 kelti laipsniu n.
program laip;
var k, n, p: integer;
begin
read(n);
p := 1;
for k := 1 to n do
p := k*2;
writeln(p)
end.
Apskaičiavę šios programos rezultatus, esant
pradiniams duomenims 0, 1, 2, gauname 1, 2, 4. Jie teisingi. Tačiau
daryti išvadą, kad programa laip teisinga, dar per anksti.
Paėmę bet kurį didesnį pradinį duomenį, įsitikinsime, kad
programos rezultatas neteisingas. Pavyzdžiui, kai n = 3,
rezultatas yra 6, o turi būti 8, nes 23 = 8.
Taigi, apsiribojus keliais pradiniais
duomenimis arba keliais jų variantais, galima praleisti kaip tik
tuos duomenis, su kuriais gaunami klaidingi rezultatai. Kitaip
tariant, su atskirais pradiniais duomenimis galima įrodyti tik tai,
kad programa klaidinga (jei ji iš tikrųjų klaidinga), o ne tai,
kad teisinga (nors iš tikrųjų ji ir yra teisinga). Todėl labai
svarbu parinkti tinkamus kontrolinius pradinius duomenis, kuriems
esant rezultatai galėtų būti neteisingi.
Apie kontrolinių duomenų parinkimą galima
paskaityti straipsnyje [6].
Klaidų ieškojimas ir taisymas kompiuteriu
vadinamas programos derinimu.
Ne visas klaidas pavyksta greitai ir lengvai
rasti. Sudėtingose programose pasitaiko giliai pasislėpusių
klaidų. Kaip jų ieškoti ir jas rasti, bendrų receptų nėra. Ieškant
klaidų programose, praverčia logika, įžvalgumas ir, žinoma,
geras dalyko programavimo išmanymas.
Atlikdami programą kompiuteriu, ne tik
aptinkame klaidas, bet pabūname jos naudotoju: paruošiame
pradinius duomenis, skaitome kompiuterio išspausdintus rezultatus,
t.y. įsitikiname, ar patogu naudotis sudarytąja programa. Praktiškai
išbandydami programą, galime patobulinti ir uždavinio formuluotę.
Tada reikia vėl grįžti prie ankstesnių programavimo darbų ir
pakoreguoti jau sudarytą programą.
Kad programa teisinga su visomis galimomis
pradinių duomenų reikšmėmis, reikia įrodyti matematiškai. Tai
padaryti kur kas sunkiau, negu patikrinti programos rezultatą su
atskiromis pradinių duomenų reikšmėmis.
4 pavyzdys. Pabandykime įsitikinti, kad
programos laipsnis (žr. 2 pavyzdį) rezultatas teisingas, ne
skaičiuodami, o išskleisdami ciklą formule, esant įvairioms
pradinio duomens reikšmėms.
p := 1;
for k := 1 to n do
p := p*2
Kai ciklas n < 1, ciklas neatliekamas
nė karto. Vadinasi, ciklas rezultato reikšmės nekeičia ir išlieka
ankstesnė jo reikšmė p = 1.
Kai n > 1, ciklas kartojamas n kartų.
Vadinasi,
p = 1 ×
2,
kai n = 1,
p = 1 × 2 × 2,
kai n = 2,
p = 1 × 2 × 2 × 2, kai n = 3.
Nesunku padaryti išvadą, kad
p = 1 × 2 × 2 × ... ×2
n kartų
su kiekvienu n. Tai reiškia, kad p
= 2n.
Uždaviniai
5.4.1. Duoti du sąlyginiai sakiniai
1) if a > 0 then b := 5
else b := 10;
2) if a < 0 then b := 10
else b := 5;
Kokiai kintamojo a reikšmei esant jie
neekvivalentūs (t.y. jų rezultatai skirtingi)?
5.4.2. Kintamojo a reikšmė iš anksto
nežinoma. Nurodykite sąlygas, kurias tenkins
kintamojo reikšmė
atlikus šiuos sakinius:
a) if a > 10 then a := 10
else a := a + 5
b) if a > 10 then a := 1
else a := 0
5.4.3. Kintamojo a reikšmė iš
anksto nežinoma. Nurodykite sąlygas, kurias tenkins
kintamojo reikšmė
atlikus šiuos sakinius:
a) while a > 10 do
a := a-1
b) while a > 10 do
a := a-10
5.4.4. Kokias sąlygas turi tenkinti
kintamojo k reikšmė, kad būtų baigtiniai šie ciklai:
a) while c < 0 do
c := c+k
a) while k <> 0 do
k := k+1
a) while k <> 0 do
k := k-2
|
5.5. Programos tobulinimas
|
Ne iš karto pavyksta sudaryti grakščią ir
ekonomišką programą. Kai programa sudaryta, netgi patikrinta, dažnai
gimsta naujų idėjų programai patobulinti padaryti ją
trumpesnę, lakoniškesnę, aiškesnę arba ekonomiškesnę (pavyzdžiui,
greičiau atliekamą).
1 pavyzdys. Tarkime, skaičiaus moduliui
rasti buvo parašytas šitoks sakinys:
if a >= 0 then b := a
else if a < 0 then b := -a
Nesunku pastebėti, kad antroji sąlyginio
sakinio dalis apima visus tuos atvejus, kurie netenkina pirmosios sąlygos
(a >= 0). Todėl sakinį galima užrašyti trumpiau (ir aiškiau):
if a >= 0 then b := a
else b := -a
2 pavyzdys. Turime ciklą:
for k := 1 to 1000 do
s := s + p + k*k
Kiekvieną kartą atliekant jį, prie kintamojo
s reikšmės pridedama ta pati kintamojo p reikšmė.
Todėl sudėtį galima iškelti iš ciklo, pakeitus ją daugyba:
s := s + 1000*p;
for k := 1 to 1000 do
s := s + k*k
Dabar 1000 sudėčių bus pakeista viena
daugyba, todėl kompiuteris programą atliks greičiau.
Programos rašymas, tikrinimas ir tobulinimas
yra tarpusavyje glaudžiai susiję. Patobulinę patikrintą programą,
vėl turime ją tikrinti, nes tobulindami gaėjome padaryti naujų
klaidų. Jas pataisius gali vėl atsirasti tobulintinų vietų.
Kartais tobulinant ir taisant klaidas, programoje atsiranda tiek
daug pakeitimų ir užlopytų vietų, kad ją geriau parašyti
iš naujo.
Programuotojas, rašydamas programą, pripranta
prie jos ir nepastebi trūkumų. Dažnai programą pavyksta
patobulinti, kai ją skaitome praėjus ilgesniam laikui nuo jos rašymo.
Tada būname ją primiršę ir geriau sekasi viską pergalvoti iš
naujo. Trūkumus lengviau pastebėti ir kito programuotojo
sudarytoje programoje.
|
5.6. Programavimo stilius
|
Naudotojas naudoja programą savo uždaviniams
spręsti. Jam svarbu, kokį uždavinį sprendžia ta programa, kaip
pateikti pradinius duomenis kompiuteriui ir kaip kompiuteris išspausdins
rezultatus. Kadangi duomenų skaitymo ir rašymo veiksmai nurodomi
programoje, tai naudotojui geresnė ta programa, kuriai paprasčiau
paruošti pradinius duomenis ir kuri patogiau (vaizdžiau) išspausdins
rezultatus.
Programą sudaro programuotojas, ją atlieka
kompiuteris, o ja naudojasi žmogus naudotojas (25 pav.).
Vadinasi, programą galima vertinti programuotojo, kompiuterio ir
naudotojo požiūriu.
25 pav. Programuotojo, naudotojo ir kompiuterio
sąryšis
Naudotojas naudoja programą savo uždaviniams
spręsti. Jam svarbu, kokį uždavinį sprendžia ta programa, kaip
pateikti pradinius duomenis kompiuteriui ir kaip kompiuteris pateiks
rezultatus. Kadangi duomenų skaitymo ir rašymo veiksmai nurodomi
programoje, tai naudotojui geresnė ta programa, kuriai paprasčiau
paruošti pradinius duomenis ir kuri patogiau (vaizdžiau) parodys
(išspausdins) rezultatus.
1 pavyzdys. Pateikiame dvi programas tam
pačiam uždaviniui spręsti dviem laiko intervalams, išreikštiems
valandomis ir minutėmis, sudėti.
program laikas1;
var ah,
amin,
{ pirmas intervalas, val., min. }
bh,
bmin,
{ antras intervalas, val., min. }
h, min:
integer; { intervalų suma,
val., min. }
begin
read(ah, amin, bh, bmin);
min := ah*60 + amin + bh*60 + bmin;
h := min div 60;
min := min mod 60;
writeln(h, min: 3)
end.
program laikas2;
var ah,
amin,
{ pirmas intervalas, val., min. }
bh,
bmin,
{ antras intervalas, val., min. }
h, min:
integer; { intervalų suma, val., min. }
begin
read(ah, bh, amin, bmin);
min := ah*60 + amin + bh*60 + bmin;
h := min div 60;
min := min mod 60;
writeln(h, min: 3)
end.
Programos skiriasi tik pradinių duomenų
pateikimo tvarka. Be abejo, racionaliau išdėstyti pradiniai
duomenys programoje laikas1 čia pirmiau eina pirmojo
intervalo valandos ir minutės, po to antrojo intervalo valandos ir
minutės. Todėl naudotojas geriau pasirinks programą laikas1.
Programos tekstas naudotojo nedomina jis
gali net nemokėti jo perskaityti. Jam reikalinga tik trumpa
informacija, kaip pateikti pradinius duomenis ir kokius rezultatus
jis gaus. Tokia informacija vadinama naudojimosi programa
instrukcija. Programos laikas1 ji būtų maždaug tokia:
Programa laikas1 skirta dviem laiko
intervalams sumuoti. Pradiniai duomenys 4 sveikieji skaičiai,
pateikiami šitokia tvarka: pirmojo intervalo valandos ir minutės,
antrojo intervalo valandos ir minutės. Rezultatai laiko
intervalų suma: pirmiau valandos, po to minutės.
Kompiuteris atlieka veiksmus, surašytus
programoje, formaliai, paraidžiui. Todėl jo požiūriu programos
vaizdumas ar duomenų paruošimo patogumas neturi prasmės. Tačiau
kompiuteriui svarbus programos ekonomiškumas. Iš tikrųjų
programos ekonomiškumas svarbus naudotojui (ne kompiuteriui). Tik
šis parametras siejasi su kompiuterio parametrais (skaičiavimų
greičiu ir atmintinės kiekiu). Todėl kompiuterio požiūriu
geresnė programa yra ta, kuriai mažiau reikia atmintinės (mažiau
kintamųjų) ir mažiau veiksmų (ypač mažesnis ciklų
kartojimų skaičius).
2 pavyzdys. Pateikiame dvi programas
aritmetinės progresijos pirmųjų 100 narių sumai rasti. Abiejų
programų pradiniai duomenys tie patys pirmasis narys ir
skirtumas.
program prog;
const n =
100;
{ sumuojamų narių skaičius }
var
a1,
{ pirmasis narys }
aj,
{ narys }
d,
{ skirtumas }
suma,
{ narių suma }
j: integer;
begin
read(a1, d);
suma := a1; aj := a1;
for j := 2 to n do
begin
aj := aj + a1;
suma := suma + aj
end;
writeln(suma)
end.
program progresija;
const n =
100;
{ sumuojamų narių skaičius }
var a1,
{ pirmasis narys }
an,
{ paskutinis narys }
d,
{ skirtumas }
suma:
integer;
{ narių suma }
begin
read(a1, d);
an := a1 + (n-1)*d;
suma := n * (a1 + an) div 2;
writeln(suma)
end.
Aišku, ekonomiškesnė yra programa progresija,
kurioje progresijos narių suma skaičiuojama pagal formules, be
ciklo.
Programuotojas rašo programą
kompiuteriui. Atrodytų, kad mes esame programų kūrėjai, o
kompiuteris jų skaitytojas ir atlikėjas. Kompiuteris tikrai
yra programų atlikėjas. Tačiau programas skaito ir žmogus, norėdamas
sužinoti, kokie veiksmai užrašyti joje, pasisemti patirties iš
jau sudarytų programų, kai mokosi programuoti, kai sudaro naujas
programas naudodamasis jau sudarytų programų tekstais. Programas
tenka skaityti, kai jos tobulinamos, kai taisomos klaidos, kai
pritaikomos naujiems uždaviniams. Taigi ir pačiam programos
autoriui dažnai tenka pabūti jos skaitytoju nuolat grįžti
prie anksčiau sudarytų ir jau pamirštų programos dalių.
Taigi rašant programą, reikia nuolat galvoti,
kad ją nagrinės žmogus ir įsivaizduoti esant jos skaitytoju. Todėl
reikia stengtis, kad programa turi būti aiški, lengvai suprantama.
Kai programa aiški, joje mažiau būna ir klaidų, mažiau tamsių
vietų klaidoms pasislėpti.
Norint parašyti gerai suprantamą ir lengvai
skaitomą programą, reikia daugiau pastangų. Tačiau sugaištas
laikas beveik visada atsiperka: programa rašoma vieną kartą, o
skaitoma daug kartų, programą rašo vienas žmogus, o skaito
daugelis.
Taigi programuotojo požiūriu vertingesnė yra
aiškesnė ir vaizdesnė programa. Šis vertinimo kriterijus gali
prieštarauti kompiuteriniam: tam, kad programa būtų aiškesnė,
kartais reikia daugiau kintamųjų arba suprantamesnių, bet lėčiau
atliekamų veiksmų. Bet kompiuterių greitis ir atmintinė nuolat
didėja, todėl kuriant programas vis dažniau atsižvelgiama į žmogaus
poreikius. Pagaliau kompiuteris tarnauja žmogui, o ne atvirkščiai.
Taigi programos kokybę reikia vertinti trimis
požiūriais:
1) programuotojo (programos teksto
skaitytojo),
2) programos naudotojo ir
3) kompiuterio.
Bet kokiu atveju programa turi būti teisinga
negalima kalbėti apie programos kokybę, jeigu ji neteisinga,
arba švelniau pasakius sprendžia ne tą uždavinį, kurio buvo
tikėtasi.
|
5.7. Rezultatų apipavidalinimas
|
Savaime aišku, kad turi būti patogu naudotis
programa. Iš programos teikiamų pranešimų jam turi būti aišku,
ką kiekvienu momentu jis turi daryti, kokius pradinius duomenis
pateikti. Rezultatai turi būti išduodami aiškiu ir suprantamu
pavidalu.
Jeigu programą numatoma dažniau ir ilgiau
naudoti, tai reikia stengtis jos rezultatus pateikti kuo vaizdžiau,
su paaiškinimais. Rašydami programą sugaišime daugiau laiko, tačiau
ja bus lengviau naudotis. Kompiuteris gali ne tik apskaičiuoti
rezultatus, bet ir spausdinti visiškai parengtus dokumentus
algalapius, žiniaraščius, tvarkaraščius ir pan. Kaip tai
padaryti pailiustruosime pavyzdžiu.
Pavyzdys. Programa duoto intervalo sveikųjų
skaičių kvadratų ir kubų lentelei spausdinti.
program KvadrataiKubai;
var nuo, iki, { skaičių intervalas }
n: integer;
begin
read(nuo, iki);
for n := nuo to iki do
writeln(n: 5, n*n: 5, n*n*n: 5);
end.
Jeigu šiai programai pateiktume pradinius
duomenis
20 30
tai kompiuterio ekrane pamatytume šitokius
rezultatus:
20 400
8000
21 441 9261
22 484 10648
23 529 12167
24 576 13824
25 625 15625
26 676 17576
27 729 19683
28 784 21952
29 841 24389
30 900 27000
Kai domimės tik algoritmu ir eksperimentuojame
su kompiuteriu, tai toks rezultatų pavaizdavimas mus tenkina. Tuo
tarpu jeigu programą planuotume platinti naudotojams, reikėtų,
kad naudotojas matytų, ką ši programa skaičiuoja, kokių pradinių
duomenų jai reikia, o rezultatai turėtų būti pateikti vaizdžiau,
pavyzdžiui lentele. Papildysime programą visais šiais naudotojui
reikalingais komponentais.
program KvadrataiKubai;
var nuo, iki, { skaičių intervalas }
n: integer;
begin
writeln('Programa duoto intervalo skaičių');
writeln('kvadratams ir kubams skaičiuoti');
writeln;
write('Intervalo pradžia: ');
read(nuo);
write('Intervalo pabaiga: ');
read(iki);
writeln;
writeln(' Kvadratai ir kubai ');
writeln;
writeln('+-------+--------+--------+');
writeln(' :
:
: :');
writeln(' : n : n*n : n*n*n
:');
writeln(' :
:
: :');
writeln('+-------+--------+--------+');
for n := nuo to iki do
writeln(' : ', n: 5, ' : ', n*n: 5, ' : ', n*n*n: 5,'
:');
writeln('+-------+--------+--------+')
end.
Dabar kompiuteris informuos apie tai ką ši
programa skaičiuoja, paprašys pradinių duomenų: intervalo pradžios
ir pabaigos. Pasibaigus programai ekrane matysime štai tokį vaizdą:
Programa duoto intervalo skaičių
kvadratams ir kubams skaičiuoti
Intervalo pradžia: 20
Intervalo pabaiga: 30
Kvadratai ir kubai
+-------+-------+----------+
:
:
: :
: n : n*n : n*n*n
:
:
:
: :
+-------+-------+----------+
: 20 : 400 : 8000 :
: 21 : 441 : 9261 :
: 22 : 484 : 10648 :
: 23 : 529 : 12167 :
: 24 : 576 : 13824 :
: 25 : 625 : 15625 :
: 26 : 676 : 17576 :
: 27 : 729 : 19683 :
: 28 : 784 : 21952 :
: 29 : 841 : 24389 :
: 30 : 900 : 27000 :
+------+-------+----------+
Lentelės rėmeliai dar nelabai gražūs
jie sudaryti iš simbolių, kuriuos galima surinkti kompiuterio
klaviatūra. Gražesnę lentelę galima padaryti iš pseudografikos
ženklų. Tą pačią programą pakeisime taip, kad kompiuteris
lentelės rėmelius sudarytų iš pseudografikos ženklų.
program KvadrataiKubai;
var nuo, iki, n: integer;
begin
writeln('Programa duoto intervalo skaičių');
writeln('kvadratams ir kubams skaičiuoti');
writeln;
write('Intervalo pradžia: ');
read(nuo);
write('Intervalo pabaiga: ');
read(iki);
writeln(' Kvadratai ir kubai ');
writeln;
writeln('╔═══════╤═══════╤═══════╗');
writeln('║
│
│
║ ');
writeln('║
n │
n*n │ n*n*n
║');
writeln('║
│
│
║');
writeln('╠═══════╪═══════╪═══════╣');
for n := nuo to iki do
writeln(' ║ ', n:5,
' │ ', n*n:5, ' │
', n*n*n:5, ' ║');
writeln('╚═══════╧═══════╧═══════╝')
end.
Dabar kompiuteris rezultatus pateiks surašytus
į štai tokią lentelę:
Kvadratai ir kubai
╔═══════╤═══════╤═══════╗
║
│
│
║
║
n │
n*n │ n*n*n
║
║
│
│
║
╠═══════╪═══════╪═══════╣
║
20 │
400 │ 8000 ║
║
21 │
441 │ 9261 ║
║
22 │
484 │ 10648 ║
║
23 │
529 │ 12167 ║
║
24 │
576 │ 13824 ║
║
25 │
625 │ 15625 ║
║
26 │
676 │ 17576 ║
║
27 │
729 │ 19683 ║
║
28 │
784 │ 21952 ║
║
29 │
841 │ 24389 ║
║
30 │
900 │ 27000 ║
╚═══════╧═══════╧═══════╝
Atkreipiame dėmesį į tai, kad programos
tekste lentelę formuojantys sakiniai ženklai išdėstyti taip, kad
būtų galima matyti, koks paveikslas bus piešiamas
kompiuterio ekrane.
Apipavidalinant rezultatus svarbus kiekvienas
rašomas simbolis ir kiekviena tuščia vieta (tarpas). Todėl būsimą
ekrano vaizdą geriau pirma suprojektuoti ant languoto popierio ir
po to rašyti programą. Programoje padarytos klaidos lengvai
pastebimos ją atlikus kompiuteriu.
Dar didesnes rezultatų vaizdavimo galimybes
duoda tikroji grafika (ne pseudo grafika!). Tačiau mes pagrindinį
dėmesį skirsime algoritmams ir grafikos nenagrinėsime.
Praktikos darbas
5.7.1. Daugybos lentelė. Suprojektuokite
daugybos lentelę ir sudarykite programą, kuri apskaičiuotų
lentelės elementus ir juos įrašytų į ekrane rodomą lentelę.
|
5.8. Programos teksto apipavidalinimas
|
Kompiuteriui nesvarbu, kaip išdėstytas
programos tekstas. Tačiau žmogui nagrinėti programą kur kas
lengviau, kai aiškios sakinių ribos, lengvai suvokiama programos
struktūra.
Programą lengviau skaityti, kai programos
teksto išdėstymas atspindi programos struktūrą, kai iš teksto
vaizdžiai matosi kiekvienos valdymo struktūros pradžia ir pabaiga
bei struktūrų hierarchija kaip struktūros įdėtos viena į
kitą. Tai išreiškiama programos teksto eilučių lygiavimu ir
atitraukimu nuo kairiojo puslapio krašto. Lygiavimo taisyklės
labai paprastos: lygiaverčiai sakiniai, t.y. priklausantys tai pačiai
sakinių sekai vienodai atitraukiami nuo kairiojo eilutės krašto
lygiuojami. Į sakinį įdėti kiti sakiniai (jie sudaro jau kitą,
žemesnį, hierarchijos lygį) daugiau patraukiami į dešinę. Per
kiek ženklų patraukti į dešinę, kaip išdėstyti sakinių pradžios
ir pabaigos bazinius žodžius (pvz. begin end, case
end, repeat until), yra stiliaus
dalykas. Tačiau gero stiliaus taisyklės reikalauja, kad visos
programos tekstas būtų išdėstytas pagal vienodas taisykles. Šioje
knygoje kiekvieną naują sakinių hierarchijos lygį pradedame su
nemažesniu kaip dviejų pozicijų poslinkiu į dešinę, kiekvieną
žodį end rašome po jį atitinkančiu žodžiu begin.
Pateiksime lygiavimo schemos pavyzdį
read ...
a := ...
for ...
begin
a :=
while ...
case
...
5: repeat
if ...
then
else
b := ...
until ...
6: for ...
end;
end;
while...
if ...
write ...
Šitoks programos teksto išdėstymas primena
knygos turinį. Smulkesnių skyrelių pavadinimai daugiau patraukti
į dešinę, negu juos gaubiančių stambių skyrių.
Įvairiau lygiuojami sąlyginiai sakiniai. Kai
veiksmai šakojasi į dvi trumpai užrašomas kryptis, žodį else
rašomas po jį atitinkančiu žodžiu then, pavyzdžiui:
if a = 0 then write(a)
else
write(b)
Šakojimąsi į dvi sudėtingesnės šakas
rekomenduojama užrašyti šitaip:
if a = 0
then ...
else ...
Kai veiksmai šakojasi į daugelį krypčių,
kiekviena nauja žodžių else ir if pora šiek tiek
patraukiama į dešinę, pavyzdžiui:
if a = b then write(a+1)
else if a = c then write(a+2)
else if a = d then
write(a+3)
else
write(a)
Šitaip rašant tekstas mažiau nuslenka į dešinę.
Programą lengviau skaityti, kai vienoje eilutėje
yra vienas sakinys. Programos vaizdumas nenukenčia ir kai į vieną
eilutę sudedami keli labai trumpi ir tarpusavyje susiję sakiniai,
pavyzdžiui:
a := 0; b := 0;
Į vieną eilutę galima parašyti ir neigą
sudėtinį sakinį, pavyzdžiui:
begin read(a); write(a) end
Vienos eilutės tekstas taip pat turi struktūrą:
vieni žodžiai ar simboliai yra stipriau susiję, negu kiti. Sąsajų
stiprumas išreiškiamas tarpais. Tarp logiškai išsiskiriančių
simbolių, žodžių ar jų grupių, esančių vienoje eilutėje,
reikia palikti didesnį tarpą, negu tų grupių viduje. Pavyzdžiui,
po vieną tarpą rekomenduojama palikti abipus prieskyros simbolio
:=. Jeigu reiškinyje (be skliaustų) yra santykio ir aritmetinių
operacijų, tai, palikę po tarpą abipus santykio operacijų, pabrėšime,
kad jos atliekamos paskiausiai. Ta pačia taisykle reikia vadovautis
ir tada, kai tenka dalį sakinio kelti į naują eilutę: geriau
sakinį skaldyti į mažiau susijusias dalis. Pavyzdžiui:
if a - 12 = b*2
then alfa := alfa*ilgis*(plotis + sigma)
+
(a*b + c*c)
else write('Galutiniai rezultatai ',
alfa*alfa - 128: 8,
ilgis + plotis)
Daugybos ir dalybos operacijų prioritetas aukštesnis
(jos pirmiau atliekamos), negu sudėties ir atimties (jos paskiau
atliekamos). Todėl abipus sudėties ir atimties operacijų simbolių
reikėtų palikti po tarpą, o abipus daugybos ir dalybos
nepalikti. Tačiau padėti komplikuoja sveikųjų skaičių dalybos
operacijos div ir mod, žymimos žodžiais. Nepalikus
tarpų jie susilietų su gretimais kintamųjų (operandų) vardais.
Todėl kai reiškinyje yra operacijos div arba mod
tenka palikti tarpus abipus visų dviviečių operacijų simbolių.
Kitais atvejais tekstą išdėstant eilutėje
reikėtų laikytis lietuvių kalbos rašybos taisyklių. Priimta
tarpą palikti po dvitaškio, kabliataškio, kablelio, bet ne prieš
šiuos simbolius. Programose ypač svarbu palikti tarpą po kabliataškio,
nes jis skiria vieną sakinį nuo kito.
Programose kiek savitą paskirtį turi
skliaustai. Paprastaisiais skliaustais suskliaudžiami funkcijos
parametrai. Tarp funkcijos vardo atidarančio parametrų skliaustų
tarpo palikti nereikia. Mat sąsaja tarp funkcijos vardo ir jos
parametrų yra stipriausia (turi aukščiausią prioritetą.
Paliktas tarpas, pavyzdžiui,
abs (a+b)*c
sudarytų klaidingą įspūdį, kad funkcijos
parametras yra visas reiškinys ir reikia pirmiau padauginti ir po
to skaičiuoti funkcijos reikšmę. Todėl šį pavyzdį reikia
perrašyti šitaip:
abs(a+b) * c
Tarp suskliausto teksto ir skliaustų vidinių
pusių lietuvių kalboje tarpai nepaliekami. Tačiau tarpai
programose tarp komentarų ir juos gaubiančių figūrinių skliaustų
padeda atskirti komentarus nuo skliaustų. Skliaustai atlieka lyg ir
komentarų rėmelių vaidmenį, panašiai kaip ir pseudografikos
simboliai.
Kartais rėmelių vaidmenį atlieka ir dvitaškiai
aprašuose, pavyzdžiui,
var realusis : real;
seikasis : integer;
s :
char;
log : boolean;
Plačiau apie programos teksto išdėstymą rašoma
straipsnyje [7].
Uždaviniai
5.8.1. Pašalinkite nereikalingus
simbolius iš programos
program simboliai;
var a, b, i, s: integer;
begin
read(a);
i := 0; s := 0;
for i := 1 to a do
begin
s := s+(i*i)*(i+1)
end;
writeln(s);
end.
5.8.2. Su žemiau pateikta programa
atlikite šiuos veiksmus: 1) nustatykite, ką matysite
ekrane atlikę šią
programą, 2)sulygiuokite programos eilutes ir įterpkite
reikalingus
tarpus, 3) vėl
nustatykite, ką matysite ekrane atlikę šią programą.
Kurį programos tekstą: čia pateiktą ar
sutvarkytą, buvo lengviau suvokti?
program tvarka;
var i,s:integer;
begin s:=1;i:=10;
while i mod 7=0 do
i:=i - 1; s:= s+i * i;
if s > 25 then if s = 99 then s:=s
+1 else
s:=s div i-2 else s:=s- 1;writeln(s)end.
|
5.9. Programos ekonomiškumas
|
Programa yra ekonomiška jeigu ji taupiai
naudoja kompiuterio išteklius: laiką ir atmintinę.
Laikas. Sakinys į programą rašomas
vieną kartą. Kai programa vykdoma, jis gali būti atliekamas vieną
kartą, neatliekamas nė karto (jeigu, pavyzdžiui jis yra sąlyginiame
sakinyje ir pakliuvo į nevykdomą šaką) arba atliekamas daug kartų
(jeigu jis yra cikle). Aišku, kad apčiuopiamą naudą gali duoti
daug kartų atliekamų sakinių vykdymo laiko ekonomija. Tarkime,
kad sakinys S yra cikle, o tas ciklas dar kitame cikle:
for i := 1 to 1000 do
for j := 1 to 1000 do
S;
Sakinys S bus atliekamas milijoną kartų.
Taigi, kiekviena sutaupyta mikrosekundė virs visa sekunde. Todėl
reikia gerai apžiūrėti visus ciklus: ar tikrai jie reikalingi, ar
cikluose nėra tokių veiksmų, kuriuos būtų galima iškelti iš
ciklų.
1 pavyzdys. Programa nelyginių skaičių
nuo 1 iki n sumai rasti.
program NelygSuma;
var
n,
{ intervalo pabaiga }
suma,
{ nelyginių skaičių suma }
i: integer;
begin
suma := 0;
read(n);
for i := 1 to n do
if i mod 2 <> 0 then
suma := suma + i;
writeln(suma)
end.
Betgi iš eilės einantys nelyginiai skaičiai
sudaro aritmetinę progresiją. O narių sumą galima apskaičiuoti
pagal formulę
n(a1+an)
sn = ------------------
2
čia a1 pirmas narys,
an paskutinis narys,
sn narių skaičius.
Pakeitę ciklą formule, gerokai sumažinsime
programos darbo laiką.
2 pavyzdys. Tarkime kad turime šitokį
programos fragmentą:
read(a);
s := 0;
for i := 1 to n do
for j := 1 to m do
s := s + a + sqrt(1/i +
sqrt(1/j))
Kintamojo a reikšmė cikle nekeičiama. Todėl
netikslinga jo reikšmę n× m kartų (tiek kartų atliekamas
prieskyros sakinys) pridėti prie sumos s. Geriau pridėti vieną
kartą, bet padaugintą iš n × m.
Reiškinio 1/i reikšmė priklauso nuo išorinio
ciklo kintamojo i. Vidiniame cikle ji išlieka ta pati. Todėl jos
skaičiavimą galima iškelti į išorinį ciklą.
Perrašome programos fragmentą.
read(a);
s := a*n*m;
for i := 1 to n do
begin
t := 1/i;
for j := 1 to m
do
s := s
+ sqrt(t + sqrt(1/j))
end
Programos tekstas pailgėjo, bet programos
vykdymo laikas gerokai sutrumpėjo.
Tobulinant programą ekonomiškumo link
nereikia persistengti. Tuos sakinius, nuo kurie atliekami nedaug
kartų, geriau parašyti taip, kad jie būtų aiškesni skaitytojui,
nors ir keliskart lėčiau atliekami. Kompiuteris to nepajus, o
skaitytojas bus laimingas greičiau supratęs programą.
Atmintinė. Kiekvieno kintamojo reikšmei
saugoti skiriama vieta kompiuterio atmintinėje. Tačiau viena mums
jau žinomo paprastojo tipo (pvz., sveikųjų skaičių, realiųjų
skaičių) kintamajam vietos reikia tiek mažai (kelių baitų), kad
jų skaičiau mažinimas pastebimos ekonomijos neduos. Kas kita, kai
programoje naudojamos didelės duomenų struktūros (žr. 7 skyr.)
arba rekursija (žr. 8 skyr.). Todėl apie atmintinės ekonomiją
kol kas neverta kalbėti.
Uždavinys
5.9.1. Parašykite programą nelyginių
natūraliųjų skaičių sumai nuo 1 iki n rasti
naudodamiesi
aritmetinės progresijos formule.
Praktikos darbas
5.9.1. Eksperimentas. 2 pavyzdyje
pateiktus abu programos fragmentus įdėkite į programas, išbandykite
su kompiuteriu, kai n = 1000 ir m = 1000, nustatykite
jų atlikimo laikus.
|
E Ankstesnis
puslapis |
3 Turinys |
Kitas
puslapis F |
|
|
|
|