A. Considerații teoretice

Ca o extensie a limbajului Pascal standard, dialectul Turbo Pascal permite tratarea procedurilor și funcțiilor ca obiecte care pot fi atribuite unor variabile și care pot fi transmise ca parametri în proceduri și funcții. Pentru a realiza acest deziderat au fost prevazute in Turbo Pascal tipurile procedurale.

O declarație de tip procedural trebui să specifice numărul și tipul parametrilor, iar în cazul funcțiilor mai trebuie precizat și tipul rezultatului.

Exemplu:

type Proc = procedure(var x: Tablou);
     Func = function(x: real): boolean;

Reamintim că nu este permis să se declare o funcție care returnează o valoare de tip procedural (sunt permise doar tipurile scalare și tipul string).

Numele parametrilor prezenți în declarațiile de tip procedural sunt pur decorative; ele nu vor fi utilizate în continuare în cadrul programului.

Odată definit un tip procedural, se pot declara variabile de acel tip.

Exemplu:

var P1: Proc;
    F1, F2: Func;

La fel ca orice variabile, și variabilele de tip procedural își pot modifica valoarea printr-o instrucțiune de atribuire. În acest caz trebuie ca valoarea atribuită să fie o valoare de tip procedural (valoarea unei alte variabile de tip procedural sau un identificator de procedură sau funcție).

Exemplu:

Dacă avem definită o funcție, ca mai jos:

function cauta(x: real): boolean;
begin
.........
end;

putem avea următoarele atribuiri:

F2 := cauta;
F1 := F2;

Ca în orice operație de atribuire, și în acest caz, variabilele din stânga și valorile din dreapta operatorului de atribuire trebuie să fie compatibile. În cazul tipurilor procedurale aceasta înseamnă că numărul parametrilor și tipul parametrilor corespunzători trebuie să fie aceiași. În plus în cazul funcțiilor, această cerință se extinde și asupra tipului rezultatului.

Trebuie observat, că în exemplul anterior instrucțiunea:

F2 := cauta;

reprezintă atribuirea valorii procedurale cauta variabilei F2, și nu este vorba de un apel al funcției cauta.

Pentru ca o procedura sau funcție să poată fi atribuită unei variabile procedurale ea trebuie să îndeplinească următoarele condiții:

Când o valoare procedurală este asignată unei variabile procedurale se realizează, de fapt, memorarea în variabila procedurală a adresei procedurii sau funcției care este atribuită. Prin urmare, o variabilă procedurală poate fi privită asemeni unei variabile pointer, însă în loc să adreseze o dată, ea adresează o procedură sau funcție.

Trebuie reținut că tipurile procedurale pot intra în componența unor tipuri structurate, de exemplu pot apărea ca tip de bază într-un tablou sau ca tip al unui câmp într-un record.

Parametrii de tip procedural

Tipurile procedurale pot constitui (în Turbo Pascal) și tipuri posibile pentru parametrii unei proceduri sau funcții.

Dacă o procedură sau funcție apare ca parametru actual într-un apel de procedură sau funcție, ea trebuie să se supună restricțiilor menționate anterior în cazul atribuirii.

Parametrii de tip procedural sunt utilizați îndeosebi în cadrul unor subprograme (proceduri sau funcții) care codifică o anumită acțiune care trebuie extinsă la mai multe proceduri sau funcții.


B. Exemple

Să se scrie un program care sortează un tablou de elemente întregi utilizând două metode de sortare distincte. Programul va fi conceput utilizând o procedură de sortare care va avea ca parametru o procedură ce implementează o metoda de sortare specifică.

Vom utiliza două metode de sortare: sortarea prin inserție și sortarea prin interschimbare, care vor fi implementate în cadrul procedurilor Insertie, respectiv BubbleSort.

Algoritmul utilizat în cazul tehnicii de sortare prin inserție este următorul: se împarte tabloul ai, i=1,N care trebuie sortat, într-o secvență sursă și o secvență destinație. Inițial secvența destinație este formata doar din elementul a1, iar secvența sursă din elementele ai, i=2,N. Elementele din secvența sursă se introduc pe rând în secvența detinație, având graijă ca în orice moment secvența destinație să fie ordonată (la introducerea unui element se caută locul lui în secvența destinație, corespunzător valorii sale).

În cazul sortării prin interschimbare, algoritmul este următorul: se traversează în mod repetat tabloul, comparând elementele vecine: ai si ai+1, dacă elementele nu sunt în relația de ordine dorită, ele se interschimbă. Traversarea tabloului încetează în momentul în care nu se mai efectuează nici o interschimbare, deci tabloul e gata sortat.

program MetodeSortare;
const N = 10;
type 
  Index = 1..N;
  Tablou = array [Index] of integer;
  Proc = procedure(var x: Tablou);
var A: Tablou;

procedure Citeste(var x: Tablou);
var i: Index;
begin {Citeste}
  writeln('Introduceti elementele tabloului initial:');
  for i := 1 to N do begin
    write('a[', i:2, ']= ');
    readln(x[i]);
  end;
end; {Citeste}

{$F+}
procedure Insertie(var x: Tablou);
var 
  i, j: Index;
  w: integer;
begin {Insertie}
  writeln;
  writeln('INSERTIE');
  writeln;
  for i := 2 to N do begin
    j := i - 1;
    w := x[i];
    while (x[j] > w) and (j > 0) do begin
      x[j+1] := x[j];
      j := j - 1;
    end;
    x[j+1] := w;
  end;
end; {Insertie}

procedure BubbleSort(var x: Tablou);
var
  i: Index;
  aux: integer;
  sortat: boolean;
begin { BubbleSort}
  writeln;
  writeln(' BUBBLESORT ');
  writeln;
  repeat
    sortat := true;
    for i := 1 to N-1 do
      if x[i] > x[i+1] then begin
        aux := x[i];
        x[i] := x[i+1];
        x[i+1] := aux;
        sortat := false;
      end;
  until sortat;
end; {BubbleSort}
{$F-}

procedure Afiseaza(x: Tablou);
var i: Index;
begin {Afiseaza}
  for i := 1 to N do write(x[i]:6);
  writeln;
end; {Afiseaza}

procedure Sortare(x: Tablou; P: Proc);
var 
  i: Index;
  y: Tablou;
begin {Sortare}
  y :=  x;
  P(y);
  writeln('Tabloul inainte de sortare: ');
  Afiseaza(x);
  writeln ('Tabloul dupa sortare: ');
  Afiseaza(y);
end; {Sortare}

begin {programul principal}
  Citeste(A);
  Sortare(A, Insertie);
  Sortare(A, BubbleSort);
end.

C. Teme

  1. Se cere să se scrie programul care calculează rădacina pătrată a unui număr a > 0 , cu o precizie eps, fără a depăși un număr precizat n de iterații. Calculul se va realiza prin trei metode diferite. În toate cele trei cazuri rădacina se calculează ca limita unui șir al cărui termen general este:

    • la metoda lui Newton:

      (xi+1) = (1/2)*((xi)+(a/(xi)))

    • la metoda relaxarii:

      (xi+1) = (xi)+(1/(2*a))*(a-(xi)2)

    • la metoda Dedekind:

      (xi+1) = ((xi)3+3*a*(xi))/(3*(xi)2+a)

    Observații:

    • Ca aproximație inițială se ia valoarea lui a;

    • Se vor defini trei funcții distincte care calculează un nou termen al șirului, în funcție de cel anterior, conform relațiilor definite mai sus. Funcțiile vor fi toate de același tip:

      func = function(a, termen_vechi: real): real;

    • Se va defini și utiliza o funcție de calcul a rădăcinii pătrate a lui a valabilă pentru toate cele trei metode. În acest scop, ea va fi prevazută cu un parametru de tip procedural func.

     

  2. Se cere să se redacteze programul Pascal care realizează următoarele comenzi:

    • A - alege o funcție. Se precizează că programul afișează următoarle funcții din care utilizatorul poate alege una, precizând numarul ei:

      1. f(x) = sin (x) - x

      2. f(x) = x*e-arctg(b/(b+x))

      3. f(x) = sqrt (x2+x+1)*ln|x+a|

      4. f(x) = cos (x)

      5. f(x) = 2*x3 - sqrt(x)

    • I - calculează integrala funcției pe un interval precizat. Pentru calculul integralei se va folosi metoda dreptunghiurilor: se împarte intervalul în subintervale egale de lungime pas; valoarea integralei pe un interval [a,b] se calculează cu formula:

    • T - realizează tabelarea valorilor funcției pe un interval precizat;

    • X - termină programul.

    Observații:

    • La un moment dat o singura funcție este activă; operatorii I și T se referă la această funcție;

    • Valorile a, b și pas se citesc în mod independent pentru operațiile I și T.