LabOS Lesson

Implementazione Iterativa

L'analisi di un programma sequenziale in termini di grafi di dipendenza dei data ne evidenzia il possibile parallelismo. Per i programmi riportati di seguito viene presentata

Somma dei Primi Numeri Interi

La definizione dell'algoritmo è molto semplice. Indicata con S(n) la somma in questione, vale la seguente definizione ricorsiva

S(0) = 0
S(n) = S(n-1) + n
che permette di realizzare immeditamente la seguente funzione Pascal, in forma iterativa
  function nSum( N : integer ) : integer;
  var K : integer;
      S : integer;
  begin
    K := N;
    S := 0;
    while I > 0 do
      begin
        S := S + I;
        K := K - 1
      end;
    nSum := S
  end;
Il grafo di dipendenza dei dati è facilmente derivabile dall'implementazione precedente, scorporando su due cicli distinti le operazioni all'interno del ciclo while

Grafo dataflow della somma dei primi numeri interi

Per ottenere l'implementazione in Concurrent Pascal è sufficiente sostituire i due cicli computazionali del grafo dataflow con altrettante coroutine, dove

Si ha, allora, la richiesta implementazione

program nSum(input,output);
{$V+}
  
  var iC : Channel;
      xC : Event;
       N : integer;
       T : integer;
                 
  
  procedure kLoop( n : integer );
  var k : integer;
     xF : boolean;
  begin
    k := n;
    repeat
      xF := k = 0;
      Cause( xC, xF );
      if not xF then
        begin
          Send( iC, k );
          k := k - 1
        end
    until xF
  end;
  
  procedure sLoop( var s : integer );
  var k : integer;
     xF : boolean;
  begin
    s := 0;
    repeat
      Await( xC, xF );
      if not xF then
        begin
          Receive( iC, k );
          s := s + k
        end
    until xF
  end;
  
begin
  InitChannel( iC );
  StartEvent( xC );
  writeln;
  writeln('Somma dei primi n numeri interi');
  writeln;
  write('Enter N : ');
  readln( N );
  cobegin
    kLoop( N );
    sLoop( T )
  coend;
  writeln('nSum(', N:1, ') = ', T:1 )
end.

Divisione Intera

La struttura dello schema computazionale è molto semplice e si basa sul noto algoritmo di Euclide. Indicati con n ed m due interi qualunque, purchè il secondo non sia nullo, la loro divisione intera n/m deve fornire un'unica coppia di interi q ed r tali che

[ n = m*q + r ] &[ 0 <= r < n ]

Tralasciando di scrivere l'ovvia funzione Pascal, in forma iterativa, è presto visto che l'implementazione concorrente deve essere caratterizzata da due cicli computazionali

Grafo dataflow della divisione intera

program IDiv(input,output);
{$V+}
  
  var xC : Event;
       A : integer;
       B : integer;
       T : integer;
                   
  procedure rLoop( N : integer; M : integer );
  var R : integer;
     xF : boolean;
  begin
    R := N;
    repeat
      xF := R < M;
      Cause( xC, xF );
      if not xF then R := R - M
    until xF
  end;
  
  procedure qLoop( var Q : integer );
  var xF : boolean;
  begin
    Q := 0;
    repeat
      Await( xC, xF );
      if not xF then Q := Q + 1
    until xF
  end;
  
begin
  StartEvent( xC );
  writeln;
  writeln('Calcolo della Divisione Intera');
  writeln;
  write('Enter N, M : ');
  readln( A, B );
  cobegin
    rLoop( A, B );
    qLoop( T )
  coend;
  writeln( A:1,' div ', B:1, ' = ', T:1 )
end.

Radice Quadrata Intera

La definizione dell'algoritmo è simile a quello già noto per la divisione intera. Indicata con Sqrt(n) la radice quadrata intera, vale la seguente definizione

[ Sqrt(n)*Sqrt(n) + q = n ] &[ 0 <= q <= 2*n ]

che permette di realizzare immeditamente la seguente funzione Pascal, in forma iterativa

  function Sqrt( N : integer ) : integer;
  var I : integer;
      P : integer;
      K : integer;
  begin
    I := 0;
    P := 1;
    K := 0;
    while N > K do
      begin
        I := I + 1;
        P := P + 2;
        K := K + P
      end;
    Sqrt := I
  end;

Il grafo di dipendenza dei dati è facilmente derivabile dall'implementazione precedente, scorporando le operazioni all'interno del ciclo while su tre cicli distinti

Grafo dataflow della radice quadrata intera

Per ottenere l'implementazione in Concurrent Pascal è sufficiente sostituire i tre cicli del grafo dataflow con altrettante coroutine, dove

program DoSqrt(input,output);
{$V+}
  
  var pC : Channel;
      xC1 : Event;
      xC2 : Event;
      kC : Channel;
       N : integer;
       T : integer;
  
  procedure kLoop( N : integer );
  var K : integer;
      P : integer;
     xF : boolean;
  begin
    K := 1;
    repeat
      xF := K > N;
      Cause(xC1, xF );
      Cause(xC2, xF );
      if not xF then
        begin
          Receive( pC, P );
          K := K + P;
        end
      until xF
  end;
  
  procedure pLoop;
  var P : integer;
      K : integer;
     xF : boolean;
  begin
    P := 1;
    repeat
      Await( xC1, xF );
      if not xF then
        begin
          P := P + 2;
          Send( pC, P )
        end
    until xF
  end;
  
  procedure iLoop( var I : integer );
  var  xF : boolean;
  begin
    I := 1;
    repeat
      Await( xC2, xF );
      if not xF then I := I + 1
    until xF;
    I := I - 1
  end;
  
begin
  InitChannel( pC );
  InitChannel( kC );
  StartEvent( xC1 );
  StartEvent( xC2 );
  writeln;
  writeln('Calcolo della radice quadrata intera');
  write('Enter N : ');
  readln( N );
  cobegin
    kLoop( N );
    pLoop;
    iLoop( T )
  coend;
  write('Sqrt[', N:1, '] = ', T:1 );
  writeln
end.