BCX (user guide: https://hpc. cineca Collegarsi alla macchina host: bc.bcx.cineca.it user: aco2cp02 password: hlz7xMaJ ( da linux collegarsi con ssh –X aco2cp02@bc.bcx.cineca.it ) Creare una propria directory su SCRATCH in cui lavorare cd $CINECA_SCRATCH mkdir <nome directory> cd <nome directory> Caricare il modulo del compilatore module avail fornisce la lista di moduli disponibili (compilatori, tools, programmi, librerie) module load gnu/4.1.2 Per compilare: g++ main.cpp … –o <nome eseguibile>
Un esercizio: Matrix
Obiettivo Implementare un dato di tipo matrice che supporti le seguenti funzionalità: Scelta del tipo degli elementi; Scelta delle dimensioni; Accesso in lettura/scrittura ai singoli elementi; Stampa in forma tabellare. Mat = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Si propongono varie implementazioni via via più evolute.
Procedurale inizialmente il problema viene risolto in forma procedurale definendo il dato come struttura e fornendo le opportune funzioni di gestione (allocazione/deallocazione, accesso, stampa). Il tipo degli elementi è scelto dallo sviluppatore. //main.cpp #include "matrix.h" int main(int argc, char *argv[]) { const int nrows = 4; const int ncols = 5; Matrix *mat; mat = MatrixCreate(nrows, ncols); for (int i = 0; i < nrows; i++) for(int j = 0; j < ncols; j++) MatrixSetValue(mat, i, j, 1 + j + i * ncols); MatrixPrint(mat); MatrixDestroy(mat); return 0; }
A oggetti Matrix mat(nrows, ncols); Il dato viene definito come oggetto: le attività di allocazione/deallocazione vengono espletate nel costruttore/distruttore mentre le funzioni di accesso e stampa vengono tradotte nei corrispondenti metodi. //main.cpp #include "matrix.h" int main(int argc, char *argv[]) { const int nrows = 4; const int ncols = 5; Matrix mat(nrows, ncols); for (int i = 0; i < nrows; i++) for(int j = 0; j < ncols; j++) mat.SetValue(i, j, 1 + j + i * ncols); mat.Print(); return 0; }
Con riferimenti I metodi di accesso vengono unificati usando riferimenti agli elementi. //main.cpp #include "matrix.h" int main(int argc, char *argv[]) { const int nrows = 4; const int ncols = 5; Matrix mat(nrows, ncols); for (int i = 0; i < nrows; i++) for(int j = 0; j < ncols; j++) mat.Value(i, j) = 1 + j + i * ncols; mat.Print(); return 0; }
Con overloading I metodi di accesso e di stampa vengono semplificati sovraccaricando gli opportuni operatori. //main.cpp #include "matrix.h" int main(int argc, char *argv[]) { const int nrows = 4; const int ncols = 5; Matrix mat(nrows, ncols); for (int i = 0; i < nrows; i++) for(int j = 0; j < ncols; j++) mat(i, j) = 1 + j + i * ncols; cout << mat; return 0; }
Con classi derivate DenseMatrix densemat(nrows, ncols); for (i = 0; i < nrows; i++) for(j = 0; j < ncols; j++) densemat(i, j) = 1 + j + i * ncols; cout << "dense matrix\n" << densemat; SparseMatrix sparsemat(nrows, ncols); for (i = 0; i < nrows; i++) if (i % 2 - j % 2) sparsemat(i, j) = 1 + j + i * ncols; cout << "sparse matrix\n" << sparsemat; return 0; } L’oggetto matrice viene specializzato nella versione densa e sparsa. L’operatore di accesso diviene puramente virtuale. Gli elementi vengono memorizzati negli opportuni contenitori della libreria standard. //main.cpp #include "densematrix.h" #include "sparsematrix.h" int main(int argc, char *argv[]) { const int nrows = 4; const int ncols = 5; int i, j;
e infine … parametriche Le classi matrici vengono parametrizzate rispetto al tipo degli elementi in modo che questo possa essere scelto dall’utente. //main.cpp #include "densematrix.h" #include "sparsematrix.h" int main(int argc, char *argv[]) { const int nrows = 4; const int ncols = 5; int i, j; DenseMatrix<float> densemat(nrows, ncols); for (i = 0; i < nrows; i++) for(j = 0; j < ncols; j++) densemat(i, j) = 1 + j + i * ncols; cout << "dense matrix\n" << densemat; SparseMatrix<int> sparsemat(nrows, ncols); if (i % 2 - j % 2) sparsemat(i, j) = 1 + j + i * ncols; cout << "sparse matrix\n" << sparsemat; return 0; }