riduzione a operazioni scalari

2
Riduzione a operazioni scalari. Prendo i vettori, li divido in due e applico questo approccio via via al vettore risultato che viene prodotto, dimezzando sempre le due componenti che vengono sommate. Pensando a questo algoritmo con un linguaggio di alto livello, può essere espresso nel seguente modo: abbiano N iterazioni, ciascuna iterazione aggiunge al sommatore un elemento del vettore e, questa cosa, non può essere vettorializzata, perché si crea una dipendenza di calcolo. La somma viene a calcolarsi e, solo quando l'accumulatore è stato aggiornato, posso sommare un nuovo elemento del vettore e via dicendo. Se organizziamo lo schema in questo modo, abbiamo un primo vettore di accumulatori a cui viene sommato, elemento per elemento, un particolare elemento di un vettore. Viene calcolata la prima somma come elemento di posto 0 del vettore somma + elemento di posto N/2+1 (del vettore A). Mentre la somma si calcola, non necessariamente dovremo aspettare che si calcoli il risultato, perché posso fare il calcolo di sum+1 con il vettore A N/2+1 e anche sum+2 con A N/2+2, e via dicendo. Abbiamo il vettore A, la metà di questo vettore A viene copiata nel vettore sum (quindi A(0) corrisponde a sum+0). A di N/2 diventa il primo elemento di un nuovo vettore A con i che va da 0 a < N. Per cui questo diventerà il nuovo vettore A, "a costo zero". Per fare una determinata somma non devo aspettare il risultato della somma precedente, mentre quando avevamo gli elementi del vettore da sommare, dovevamo ottenere il risultato precedente, da sommare al corrente, per avere il successivo. Nel vettore A, in una prima metà e seconda metà, troviamo il primo for che calcola un vettore che ha N/2 elementi, perché va da 0 a VL-1. La 1° iterazione inizializza il vettore sum con il vettore A, in cui trattiamo il vettore sum da 0 a VL-1. E' come se il vettore da 0 a VL-1 ( già metà) si aggiorna con se stesso, sommato la 2 metà del vettore; invece Il vettore sum da VL a 2(VL-1), che sarebbe la dimensione originale . Stiamo quindi prendendo il vettore da 0 a VL/2 e stiamo sommando lo stesso vettore da N/2+1 a N. Strutturato così, il while, gestisce il progressivo dimezzamento, perché una volta aver eseguito l'operazione per ogni elemento del vettore, svolgiamo questo ciclo fino a VL>1. Alla prossima iterazione VL viene dimezzato, il vettore sum che inizialmente era a VL/2 ma dopo la prima iterazione è ancora metà, Il primo for essenzialmente crea il vettore sum che viene a manipolarsi,

Upload: vittorio-troise

Post on 01-Feb-2016

2 views

Category:

Documents


0 download

DESCRIPTION

Lezione di calcolatori elettronici tenute dal prof. Marino Poliba

TRANSCRIPT

Page 1: Riduzione a Operazioni Scalari

Riduzione a operazioni scalari.

Prendo i vettori, li divido in due e applico questo approccio via via al vettore risultato che viene prodotto, dimezzando sempre le due componenti che vengono sommate. Pensando a questo algoritmo con un linguaggio di alto livello, può essere espresso nel seguente modo: abbiano N iterazioni, ciascuna iterazione aggiunge al sommatore un elemento del vettore e, questa cosa, non può essere vettorializzata, perché si crea una dipendenza di calcolo. La somma viene a calcolarsi e, solo quando l'accumulatore è stato aggiornato, posso sommare un nuovo elemento del vettore e via dicendo. Se organizziamo lo schema in questo modo, abbiamo un primo vettore di accumulatori a cui viene sommato, elemento per elemento, un particolare elemento di un vettore. Viene calcolata la prima somma come elemento di posto 0 del vettore somma + elemento di posto N/2+1 (del vettore A). Mentre la somma si calcola, non necessariamente dovremo aspettare che si calcoli il risultato, perché posso fare il calcolo di sum+1 con il vettore A N/2+1 e anche sum+2 con A N/2+2, e via dicendo. Abbiamo il vettore A, la metà di questo vettore A viene copiata nel vettore sum (quindi A(0) corrisponde a sum+0). A di N/2 diventa il primo elemento di un nuovo vettore A con i che va da 0 a < N. Per cui questo diventerà il nuovo vettore A, "a costo zero". Per fare una determinata somma non devo aspettare il risultato della somma precedente, mentre quando avevamo gli elementi del vettore da sommare, dovevamo ottenere il risultato precedente, da sommare al corrente, per avere il successivo. Nel vettore A, in una prima metà e seconda metà, troviamo il primo for che calcola un vettore che ha N/2 elementi, perché va da 0 a VL-1. La 1° iterazione inizializza il vettore sum con il vettore A, in cui trattiamo il vettore sum da 0 a VL-1. E' come se il vettore da 0 a VL-1 ( già metà) si aggiorna con se stesso, sommato la 2 metà del vettore; invece Il vettore sum da VL a 2(VL-1), che sarebbe la dimensione originale. Stiamo quindi prendendo il vettore da 0 a VL/2 e stiamo sommando lo stesso vettore da N/2+1 a N. Strutturato così, il while, gestisce il progressivo dimezzamento, perché una volta aver eseguito l'operazione per ogni elemento del vettore, svolgiamo questo ciclo fino a VL>1. Alla prossima iterazione VL viene dimezzato, il vettore sum che inizialmente era a VL/2 ma dopo la prima iterazione è ancora metà, Il primo for essenzialmente crea il vettore sum che viene a manipolarsi, quello che effettivamente viene svolto come calcolo è la seconda parte del codice. Quello che osserveremo è che l'operazione va fatta con una singola operazione vettoriale che riguarderà VLR elementi dove VLR è il registro che dice quanti elementi considerare e ogni iterazione questo VLR si dimezzerà. Possiamo scrivere il codice:Supponiamo in VLR 64, abbiamo questo registro vettoriale:disegno2

Quello che si può pensare di fare, anche se crea traffico sulla memoria, è caricare dalla memoria il vettore. Carico la prima metà in un vettore, la seconda in un altro ottenendo 2 vettori. Li sommo e, dato che non troviamo un'operazione, il passaggio forzato è andare in memoria. Poi si va in memoria a rileggere questa parte. Si potrebbe caricare anche una metà in un vettore e l'altra metà in un altro vettore ancora, ma non è la cosa migliore. L'algoritmo potrebbe essere di aver caricato i due vettori in partenza, fare la somma in un vettore (che potrebbe anche essere lo stesso che consideriamo), fare lo STORE del vettore in memoria, dimezzare VLR e fare la LOAD del vettore.

Page 2: Riduzione a Operazioni Scalari

Sommare un vettore sulla sua metà ripiegata: per sommarlo dobbiamo caricare in un operando vettore una parte, l'altra su un altro operando. Poi dobbiamo sommare e il risultato a sua volta verrà ripiegato. Il problema è prendere il vettore e caricare le due metà: una parte va nella 1° metà del vettore. Siccome quest’ operazione non si può fare tra vettore e vettore, dovremo passare dalla memoria. Scriveremo in memoria il vettore e da lì lo prenderemo. Per fare questo, non possiamo scrivere in memoria solo il pezzo di vettore, ma potremmo fare un vettor mask, dove la seconda metà è uguale a 1 e fare la STORE del pezzo in memoria Più veloce, ma momentaneamente ragiono senza vettor mask. Dopo aver caricato, in memoria, il vettore a partire da un certo indirizzo devo dimezzare VLR e punto adesso per fare la LOAD non a Rbase ma a Rbase + VLR( per una LOAD di questi elementi). Li metterò in un nuovo registro. Gli altri non c'è bisogno che li carico perché già presenti. Ora posso fare la somma tra i 2 vettori, somma che dura VLR. Il risultato lo scrivo in maniera tale da avere già la somma del vettore ripiegato su se stesso. Prendo il VLR e lo scrivo in memoria e ripeto tutto quello che ho fatto sino ad ora, dimezzo VLR, faccio lo STORE e cosi via. Questo processo andrà avanti fintanto che che VLR >1. Alla fine avrò un vettore di cui l'ultimo elemento, quello di posto 0, è la somma di tutti gli elementi del vettore.