Rafinarea
Rezolvarea informatica a multor probleme complexe necesita
o analiza structurata bine
facuta, cât si o proiectare
la fel de bine realizata.
Pentru a scrie programe PASCAL (rezonabile) vom avea
nevoie mereu de un algoritm.
| Schitati
pentru început actiunile neprimitive (ce urmeaza a fi
descompuse) ale algoritmului. Dupa aceea, descompuneti
(rafinati) aceste actiuni pâna când ajungeti la o
primitiva recunoscuta de calculator. |
O tehnica ce se preteaza de minune la proiectarea top -
down este stepwise refinement (rafinarea
pas cu pas). Pentru aplicarea acestei tehnici trebuie parcursi
urmatorii pasi :
- Scrieti în limba româna (engleza) o solutie simpla.
Nu va preocupati prea mult de detalii;
- Rafinati solutia folosind limbajul
pseudocod. Eliminati detaliile
suparatoare, imaginându-va ca aveti deja procedurile
care fac lucruri complicate;
- Rafinati rezultatele pasului 2 pâna când ati scris
corect programul principal PASCAL , chiar daca programul
contine mai multe referiri la procedurile care nu au fost
înca scrise;
- Codificati toate procedurile ca proceduri nule.
Compilati procedurile, eliminati erorile pâna când
obtineti o compilare corecta (curata);
- Înlocuiti cu logica necesara atâtea proceduri nule
câte sunt necesare pentru a putea realiza o executie a
programului principal ( evident, fara toate procedurile
scrise nu putem astepta raspunsurile finale, dar putem
cunoaste raspunsurile intermediare );
- Înlocuiti în mod gradat procedurile nule ramase cu
cele reale pâna când programul va opera corect.

|
Remarca:
Pentru programele mari, câtiva din
acesti pasi pot fi combinati sau pot fi facuti mintal. Cu
cât veti avea mai multa experienta, cu atât veti face
rafinari mai putine.
|
Vom exemplifica acesti pasi pe un caz concret, oferit de
urmatoarea aplicatie:
 |
Aplicatie
Sa se editeze blocuri (etichetate) de numere
întregi care reprezinta calendarul lunilor.
|
- Date de intrare: numarul
zilelor din luna (de la 1 la 31) si numarul zilei din
saptamâna în care cade întâi ale lunii (de la 1 la
7).
- Date de iesire: zilele
saptamânii (se vor lista pe orizontala). Lunile vor fi
separate printr-un rând de spatii libere. In figura 2.3
se prezinta formatul datelor de iesie.
- ..L....M....M....J....V....S....D
- ..
....1....2....3....4....5....6
- ..7....8....9...10...11...12...13
- .14...15...16...17...18...19...20
- .21...22...23...24...25...26...27
- .28...29...30...31
|
Formatul datelor de
iesire
Tabela de variabile:
| TABELA DE VARIABILE |
| Variabile de intrare |
Variabile de stare |
Variabile de iesire |
- nz: numarul de zile
ale lunii
- l_1: ziua de intâi
a lunii
|
- i: index
|
|
Utilizând metodologia stepwise
refinement vom începe prin a face analiza problemei
urmata de o solutie (în limba româna).
Pasul 1:
Prima linie a blocului de numere contine cel putin un
numar (cel mult 7) si poate începe cu blancuri (1-6) astfel
încât putem considera prima linie ca pe un caz special.
Urmatoarele trei linii sunt intotdeauna complete, chiar
daca prima zi "pica" duminica. Deci, putem tipari cele
trei linii. Si a cincea linie poate fi completa, dar nu mereu. De
asemenea, poate exista o a sasea linie pentru lunile de 30 si 31
de zile în care prima zi a lunii este ultima zi din saptamâna.
Ultimele doua situatii vor fi tratate ca pe un caz special,
fiecare.
Pasul 2:
Procedam la o rafinare a textului stabilit în pasul
anterior si elaboram algoritmul de baza listând atât actiunile
primitive cât si cele neprimitive. Pentru descrierea
algoritmului vom folosi pseudocodul,
retinând de aceasta data câteva din detaliile... suparatoare
ale primei etape.
- FOR toate lunile
anului DO
- ..BEGIN
- ....Citeste nz, l_1
- ....Tipareste zilele saptamânii
(prima litera)
- ....Tipareste o linie alba
- ....Tipareste prima linie
- ....Tipareste urmatoarele trei
linii
- ....Tipareste a-5-a linie daca
este nevoie
- ....Tipareste a-6-a linie daca
este nevoie
- ....Tipareste o linie alba
- END
Pasul 3:
Generam o prima forma a programului PASCAL în care
fiecare actiune din pseudocod este înlocuita cu un enunt
(valabil) sau cu apeluri ale unor proceduri nule (nescrise).
- PROGRAM calendar;
- VAR
- ....nz, l_1: integer;
- ....i: integer;
- BEGIN { program
principal }
- ....FOR i:=1 TO 12 DO
- ........BEGIN
- ............readln(nz, l_1)
- ............bloc;
- ............linie1(l_1);
- ............linie234(valoare de start);
- ............linie56(valoare de
start,valoare de end);
- ............linie56(valoare de
start,valoare de end);
- ............writeln
- ........END
- END {calendar}.
Programul principal
contine patru proceduri:
- bloc ( tipareste pe o linie prima
litera din zilele saptamânii si apoi o linie alba);
- linie1 (tipareste prima linie - ziua
de întâi a lunii (l_1)
este parametru efectiv);
- linie234 (tipareste urmatoarele trei
linii - procedura are nevoie numai de un parametru
efectiv (valoare de start) întrucât ea va tipari
întotdeauna 21 de numere);
- linie56 (procedura va fi apelata de
doua ori si are nevoie de doi parametri efectivi - o
valoare de start si de o valoare de end).
In aceasta etapa nu este bine sa va necajiti, facându-va
probleme ca nu aveti, înca, nici o idee despre valorile
parametrilor efectivi, declarati în program. Suntem de-abia la
începutul ... sfârsitului !
Ati remarcat ca fraza pseudocod
....."FOR toate lunile
anului DO"
s-a tradus direct în PASCAL prin:
....."FOR i:=1 TO 12
DO"?
Am ales ca structura de iteratie FOR întrucât
stim de la început ca programul va genera 12 blocuri de numere -
calendarul pentru 12 luni (am folosit ca index, variabila
întreaga "i").
V-a trecut supararea? Daca da, atunci ... sa navigam
încercând sa realizam codul PASCAL pentru câteva proceduri,
celelalte ramânând (nu pentru mult timp ) nule.
- PROGRAM calendar;
- VAR
- . i,nz,l_1:integer;
-
- PROCEDURE bloc;
- BEGIN
- . writeln;
- . writeln(..L....M....M....J....V....S....D);
- . writeln
- END { bloc }
-
- PROCEDURE
linie1(n: integer);
- VAR
- . j:integer;
- BEGIN
- . FOR j:=1 TO n-1
DO
- . . write( :5);
- . FOR j:=1 TO 8-n
DO
- . . write(j:5);
- . writeln
- END { linie1 };
-
- PROCEDURE
linie234(primul, ultimul: integer); { procedura nula }
- BEGIN
- END { linie234
};
-
- PROCEDURE
linie56(primul, ultimul:integer); { procedura nula }
- BEGIN
- END { linie56 };
-
- BEGIN { program
principal }
- . FOR i:=1 TO 12 DO
- . BEGIN
- . . writeln(introduceti
pentru luna ,i:2);
- . . write(numarul total de
zile );
- . . readln(nz);
- . . write(pozitia lui 1 in
saptamina (joi=4) );
- . . readln(l_1);
- . . bloc;
- . . linie1(l_1);
- . . linie234(9-l_1);
- . . linie56(0,0);..{ cit timp sunt intregi
argumentele }
- . . linie56(0,0);..{ nu au importanta,din moment
ce }
- . . writeln . . . { linie56 este nula }
- . END
- END {calendar}.
Încercati o compilare a programului. V-a reusit? Daca
într-adevar compilarea este corecta sa trecem si la executia
programului. Introduceti numarul de zile ale lunii (31) si ziua
de întâi a lunii (6).
Ati obtinut imaginea de mai jos?
- ..introduceti
pentru luna 1
- ..numar
total de zile 31
- ..pozitia
lui 1 in saptamana (joi=4)..6..
- ....L...M...M...J...V...S...D
- ....L...M...M...J...V...1...2
|
Daca nu, confruntati programul dumneavoastra cu cel
realizat de noi si vedeti ce lipseste. Daca ati reusit,
continuati! Daca n-ati reusit, continuati !
Trebuie sa recunoastem ca am facut într-adevar progrese.
Dar înca n-am terminat programul ! Tot ceea ce ne-a mai ramas de
facut este sa scriem codul pentru procedurile nule: linie234,
linie56 si apoi sa ne gândim la
parametrii efectivi ale caror valori sa "hraneasca"
procedurile ramase necodificate (linie234
si linie56).
Programul final este urmatorul:
- PROGRAM calendar;
- VAR
- ..i,nz,11:integer;
-
- PROCEDURE bloc;
- BEGIN
- ..writeln;
- ..writeln ( L M N J V S
D);
- ..writeln
- END { bloc };
-
- PROCEDURE
linie1(n:integer);
- VAR
- ..j:integer;
- BEGIN
- ..FOR j:=1 TO n-1
DO
- ....write ( :5);
- ..FOR j:=1 TO 8-n
DO
- ....write (j:5);
- ..writeln
- END;{ linie1 }
-
- PROCEDURE
linie234(n:integer);
- VAR
- ..i,j:integer;
- BEGIN
- ..FOR i:=1 TO 3 DO
- ..BEGIN
- ....FOR j:=1 TO 7 DO
- ....BEGIN
- ......write(n:5);
- ......n:=n+1
- ....END;
- ....writeln
- ..END;
- END; { linie234
}
-
- PROCEDURE
linie56(primul,ultimul:integer);
- VAR
- ..i,limita:integer;
- BEGIN
- ..IF
(ultimul-primul)<7 THEN
- ....limita:=ultimul
- ..ELSE
- ....limita:=primul+6;
- ..FOR i:=primul TO
limita DO
- ....write(i:5);
- ..writeln
- END; { linie56 }
-
- BEGIN {
programul principal }
- ..FOR i:=1 TO 12 DO
- ..BEGIN
- ....writeln(Introduceti
pentru luna ,i:2);
- ....write(numar total zile
);
- ....readln(nz);
- ....write(pozitia lui 1 in
saptamina (joi=4) );
- ....readln(l_1);
- ....bloc;
- ....linie1(l_1);
- ....linie234(9-l_1);
- ....linie56(30-l_1, nz);
- ....linie56(37-l_1, nz);
- ....writeln
- ..END
- END { calendar
}.
Rezultatele executiei programului:
- Introduceti
pentru luna 1
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 6
-
- ..L...M...M...J...V...S...D
-
- ......................1...2
- ..3...4...5...6...7...8...9
- .10..11..12..13..14..15..16
- .17..18..19..20..21..22..23
- .24..25..26..27..28..29..30
- .31
-
- Introduceti
pentru luna 2
- numar
total zile 28
- pozitia
lui 1 in saptamina (joi=4) 2
-
- ..L...M...M...J...V...S...D
-
- ......1...2...3...4...5...6
- ..7...8...9..10..11..12..13
- .14..15..16..17..18..19..20
- .21..22..23..24..25..26..27
- .28
-
- Introduceti
pentru luna 3
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 2
-
- ..L...M...M...J...V...S...D
-
- ......1...2...3...4...5...6
- ..7...8...9..10..11..12..13
- .14..15..16..17..18..19..20
- .21..22..23..24..25..26..27
- .28..29..30..31
-
- Introduceti
pentru luna 4
- numarul
total zile 30
- pozitia
lui 1 in saptamina (joi=4) 5
-
-
- ..L...M...M...J...V...S...D
-
- ..................1...2...3
- ..4...5...6...7...8...9..10
- .11..12..13..14..15..16..17
- .18..19..20..21..22..23..24
- .25..26..27..28..29..30
-
- Introduceti
pentru luna 5
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 7
-
- ..L...M...M...J...V...S...D
-
- ..........................1
- ..2...3...4...5...6...7...8
- ..9..10..11..12..13..14..15
- .16..17..18..19..20..21..22
- .23..24..25..26..27..28..29
- .30..31
- Introduceti
pentru luna 6
- mumar
total de zile 30
- pozitia
lui 1 in saptamina (joi=4) 3
-
- ..L...M...M...J...V...S...D
-
- ..........1...2...3...4...5
- ..6...7...8...9..10..11..12
- .13..14..15..16..17..18..19
- .20..21..22..23..24..25..26
- .27..28..29..30
-
- Introduceti
pentru luna 7
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 5
-
-
- ..L...M...M...J...V...S...D
-
- ..................1...2...3
- ..4...5...6...7...8...9..10
- .11..12..13..14..15..16..17
- .18..19..20..21..22..23..24
- .25..26..27..28..29..30..31
-
- Introduceti
pentru luna 8
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 1
-
- ..L...M...M...J...V...S...D
-
- ..1...2...3...4...5...6...7
- ..8...9..10..11..12..13..14
- .15..16..17..18..19..20..21
- .22..23..24..25..26..27..28
- .29..30..31
-
- Introduceti
pentru luna 9
- numar
total zile 30
- pozitia
lui 1 in saptamina (joi=4) 4
-
-
- ..L...M...M...J...V...S...D
-
- ..............1...2...3...4
- ..5...6...7...8...9..10..11
- .12..13..14..15..16..17..18
- .19..20..21..22..23..24..25
- .26..27..28..29..30
-
- Introduceti
pentru luna 10
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 6
-
-
- ..L...M...M...J...V...S...D
-
- ......................1...2
- ..3...4...5...6...7...8...9
- .10..11..12..13..14..15..16
- .17..18..19..20..21..22..23
- .24..25..26..27..28..29..30
- .31
- Introduceti
pentru luna 11
- numar
total zile 30
- pozitia
lui 1 in saptamina (joi=4) 2
-
- ..L...M...M...J...V...S...D
-
- ......1...2...3...4...5...6
- ..7...8...9..10..11..12..13
- .14..15..16..17..18..19..20
- .21..22..23..24..25..26..27
- .28..29..30
-
- Introduceti
pentru luna 12
- numar
total zile 31
- pozitia
lui 1 in saptamina (joi=4) 4
-
- ..L...M...M...J...V...S...D
-
- ..............1...2...3...4
- ..5...6...7...8...9..10..11
- .12..13..14..15..16..17..18
- .19..20..21..22..23..24..25
- .26..27..28..29..30..31
|