Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Prodotto riga per colonna tra due matrice
Forum - C/C++ - Prodotto riga per colonna tra due matrice

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
comtel (Member)
Pro


Messaggi: 145
Iscritto: 08/04/2011

Segnala al moderatore
Postato alle 11:14
Giovedì, 06/09/2018
Buongiorno ragazzi, so che sto inondando il forum di richieste riguardanti il C, ma scrivendo un piccolo codice per il prodotto riga per colonna tra due matrici utilizzando gli interi generati pseudocasualmente come elementi della matrice mi sono imbattuto in questo tipo di errore logico, ossia che la matrice risultante non è quella che ci si aspettava che sia. Il problema poteva stare proprio nell'elaborazione della funzione, ma l'esercizio è una versione successiva ad un altro esercizio uguale utilizzando i float come elementi pseudocasuali delle due matrici, ed in questo caso funziona perfettamente. Non so il perchè, ho anche provato ad utilizzare la calloc piuttosto che la malloc.

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4.  
  5. int * row_allocation(int *, int *, int, int, int, int);
  6.  
  7. int main(int argc, char *argv[]) {
  8.         int row1 = atoi(argv[1]), col1 = atoi(argv[2]), row2 = atoi(argv[3]), col2 = atoi(argv[4]);
  9.         int *mat1 = (int *)malloc(row1*col1*sizeof(int));
  10.         int *mat2 = (int *)malloc(row2*col2*sizeof(int));
  11.         int i, j;
  12.  
  13.         srand((unsigned int)time(NULL));
  14.  
  15.         printf("\nPrima matrice:\n");
  16.         for(i = 0; i < row1; i++) {
  17.                 for(j = 0; j < col1; j++) {
  18.                         *(mat1 + i*row1 + j) = ((int)rand())/((int)RAND_MAX/50);
  19.                         printf("%d\t", *(mat1 + i*row1 + j));  
  20.                 } printf("\n");
  21.         }
  22.  
  23.         printf("\nSeconda matrice:\n");
  24.         for(i = 0; i < row2; i++) {
  25.                 for(j = 0; j < col2; j++) {
  26.                         *(mat2 + i*row2 + j) = ((int)rand())/((int)RAND_MAX/50);
  27.                         printf("%d\t", *(mat2 + i*row2 + j));
  28.                 } printf("\n");
  29.         }
  30.  
  31.         printf("\nMatrice prodotta per righe:\n");
  32.         int *mt3 = row_allocation(mat1, mat2, row1, row2, col1, col2);
  33.         for(i = 0; i < row1; i++) {
  34.                 for(j = 0; j < col2; j++) {
  35.                         printf("%d\t", *(mt3 + i*row1 + j));
  36.                 } printf("\n");
  37.         }
  38.  
  39.         free(mat1); free(mat2); free(mt3);
  40. }
  41.  
  42. int * row_allocation(int *mat1, int *mat2, int row1, int row2, int col1, int col2) {
  43.         int *mat3 = (int *)malloc(row1*col2*sizeof(int)), i, j, z;
  44.  
  45.         for(i = 0; i < row1; i++) {
  46.                 for(j = 0; j < col2; j++) {
  47.                         for(z = 0; z < row2; z++) {
  48.                                 *(mat3 + i*row1 + j) += (*(mat1 + i*row2 + z)) * (*(mat2 + z*col2 + j));
  49.                         } printf("%d\t", *(mat3 + i*row1 + j));
  50.                 } printf("\n");
  51.         } printf("\n\n");
  52.        
  53.         return mat3;
  54. }



Inoltre vorrei sapere cosa si intende per allocazione della matrice per colonne.. Cioè, ho inteso come si visualizza una matrice per colonne, ma per allocarla non bisogna comunque utilizzare la malloc o la calloc specificando la lunghezza della porzione di memoria, ossia M*N*sizeof(tipo) indifferentemente dal tipo di allocazione della matrice ?!

Ultima modifica effettuata da comtel il 06/09/2018 alle 11:23
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 11:34
Giovedì, 06/09/2018
Posta pure l'altro esercizio.

Cmq, c'è un piccolo errore concettuale.

Codice sorgente - presumibilmente C/C++

  1. int *mat1 = (int *)malloc(row1*col1*sizeof(int));


Alloca lo spazio per un ARRAY di (row1*col1) elementi, NON una matrice.
Per la matrice PRIMA allochi le righe POI, PER OGNI RIGA, allochi lo spazio per le colonne...tipo:
Codice sorgente - presumibilmente Plain Text

  1. /*  righe (ogni elemento è un puntatore) */
  2. mat1 = (int**)malloc( row1 * sizeof(int) );
  3.  
  4. /* Colonne */
  5. for(i=0; i<row1; i++)
  6.     mat1[i] = (int*)malloc( col1 * sizeof(int) );


Ultima modifica effettuata da Mikelius il 06/09/2018 alle 12:12
PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 11:42
Giovedì, 06/09/2018
Ci sono due errori in effetti, uno di logica nella moltiplicazione, e l'altro di inizializzazione della memoria anche se meno evidente.

Controlla bene la definizione di moltiplicazione di matrice, la riga che la effettua dovrebbe essere corretta così:
Codice sorgente - presumibilmente Plain Text

  1. *(mat3 + i*row1 + j) += (*(mat1 + i*row1 + z)) * (*(mat2 + z*row2 + j));



Per quanto riguarda l'inizializzazione, dovresti assicurarti che il valore contenuto in *(mat3 + i*row1 +j) sia 0 prima di procedere a un += (che somma sul valore già presente, ma il valore già presente è indefinito)
Di solito la memoria è quasi sempre inizializzata a zero per motivi che che ti sono stati accennati nel thread su calloc, ma non c'è questa garanzia in generale.

Prima del for aggiungi una inizializzazione (oppure usa calloc). Ti consiglio per chiarezza maggiore di fare così anzi:
Codice sorgente - presumibilmente C/C++

  1. int elemento = 0;
  2. for (...) {
  3.     elemento += ...
  4. }
  5. *(mat3 + i*row1 + j) += elemento;



Lo trovo un po' più chiaro da leggere, inoltre eviti ogni volta un accesso inutile alla memoria: tecnicamente ogni volta che fai *(mat3 + i*row1 + j) fai un indirizzamento alla memoria, che è piu lento di usare una variabile locale siccome di solito il compilatore le salva in un registro. Tutto questo discorso a meno che il compilatore non se ne accorga e ottimizzi, ma ho qualche dubbio su questo.

Ultima modifica effettuata da lumo il 06/09/2018 alle 11:49
PM Quote
Avatar
comtel (Member)
Pro


Messaggi: 145
Iscritto: 08/04/2011

Segnala al moderatore
Postato alle 11:48
Giovedì, 06/09/2018
Grazie mille per la pronta risposta,
effettuerò dei test con la soluzione che lumo mi ha proposto, ed inoltre ecco qui il codice dell'altro esercizio, che a quanto ho provato e testato funziona:
Codice sorgente - presumibilmente C

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4.  
  5. float * matx_prod(float *, float *, int, int, int, int);
  6.  
  7. int main(int argc, char *argv[]) {
  8.         int row1 = atoi(argv[1]), col1 = atoi(argv[2]), row2 = atoi(argv[3]), col2 = atoi(argv[4]), i, j, z;  
  9.         float *mat1, *mat2, *mat3;
  10.         clock_t ct1, ct2;
  11.         double e_time;
  12.  
  13.         ct1 = clock();
  14.         mat1 = (float *)malloc(row1*col1*sizeof(float));
  15.         mat2 = (float *)malloc(row2*col2*sizeof(float));
  16.         ct2 = clock();
  17.         e_time = (double)(ct2 - ct1)/(double)CLOCKS_PER_SEC;
  18.  
  19.         printf("Allocazione avvenuta in %e secondi\n", e_time);
  20.  
  21.         srand((unsigned int)time(NULL));
  22.  
  23.         printf("\nPrima matrice:\n");
  24.         for(i = 0; i < row1; i++) {
  25.                 for(j = 0; j < col1; j++) {
  26.                         *(mat1 + i*row1 + j) = ((float)rand())/((float)RAND_MAX/50);   
  27.                         printf("%2.2f\t\t", *(mat1 + i*row1 + j));
  28.                 } printf("\n");
  29.         }      
  30.  
  31.         printf("\nSeconda matrice:\n");
  32.         for(i = 0; i < row2; i++) {
  33.                 for(j = 0; j < col2; j++) {
  34.                         *(mat2 + i*row2 + j) = ((float)rand())/((float)RAND_MAX/50);   
  35.                         printf("%2.2f\t\t", *(mat2 + i*row2 + j));
  36.                 } printf("\n");
  37.         }
  38.  
  39.         ct1 = clock();
  40.         float *matx3 = matx_prod(mat1, mat2, row1, col1, row2, col2);
  41.         ct2 = clock();
  42.         e_time = (double)(ct2 - ct1)/(double)CLOCKS_PER_SEC;
  43.  
  44.         printf("\nMatrice prodotta in %e secondi:\n", e_time);
  45.         for(i = 0; i < row1; i++) {
  46.                 for(j = 0; j < col2; j++) {
  47.                         printf("%2.2f\t\t", *(matx3 + i*row1 + j));
  48.                 } printf("\n");
  49.         } printf("\n");
  50. }
  51.  
  52. float * matx_prod(float *mat1, float *mat2, int row1, int col1, int row2, int col2) {
  53.         float *mat3 = (float *)malloc(row1*col2*sizeof(float));
  54.         int i, j, z;
  55.  
  56.         for(i = 0; i < row1; i++) {
  57.                 for(j = 0; j < col2; j++) {
  58.                         for(z = 0; z < row2; z++) {
  59.                                 *(mat3 + i*row1 + j) += (*(mat1 + i*row2 + z)) * (*(mat2 + z*col2 + j));
  60.                         }
  61.                 }
  62.         }      
  63.  
  64.         return mat3;
  65. }


PM Quote
Avatar
comtel (Member)
Pro


Messaggi: 145
Iscritto: 08/04/2011

Segnala al moderatore
Postato alle 11:56
Giovedì, 06/09/2018
Testo quotato

Postato originariamente da lumo:

Ci sono due errori in effetti, uno di logica nella moltiplicazione, e l'altro di inizializzazione della memoria anche se meno evidente.

Controlla bene la definizione di moltiplicazione di matrice, la riga che la effettua dovrebbe essere corretta così:
Codice sorgente - presumibilmente Plain Text

  1. *(mat3 + i*row1 + j) += (*(mat1 + i*row1 + z)) * (*(mat2 + z*row2 + j));





Osservando la riga di codice, ho fatto un test, quando i = 0; j = 0; z = 1;
Allora la riga dovrebbe essere la seguente: mat3 (ossia primo elemento della matrice risultante) = mat1 + 1 (fin qui ci siamo, ossia il secondo elemento della riga della matrice mat1) * mat2 + 3 (ossia il quarto elemento della matrice mat2, che corrisponde a quello sulla seconda colonna). Il che non dovrebbe andare bene dato che la definizione di prodotto riga per colonna è la seguente:

mat1 =
1 2 3
4 5 6

mat2 =
1 2
3 4
5 6

quindi il primo elemento della matrice risultante dovrebbe essere questo => elemento(1:1) = (1*1 + 2*3 + 3*5).. E così via.

Interessante è però la tua osservazione sulla inizializzazione dell'elemento prima di utilizzarlo, anche se ho utilizzato anche una calloc, che inizializza gli elementi a 0 al suo richiamo. La tua logica di non accedere sempre alla memoria ad ogni passo del ciclo è giusta, ma comunque non ha risolto il mio problema.

Ultima modifica effettuata da comtel il 06/09/2018 alle 12:04
PM Quote
Avatar
comtel (Member)
Pro


Messaggi: 145
Iscritto: 08/04/2011

Segnala al moderatore
Postato alle 12:01
Giovedì, 06/09/2018
Testo quotato

Postato originariamente da Mikelius:

Posta pure l'altro esercizio.

Cmq, c'è un piccolo errore concettuale.

Codice sorgente - presumibilmente C/C++

  1. int *mat1 = (int *)malloc(row1*col1*sizeof(int));


Alloca lo spazio per un ARRAY di (row1*col1) elementi, NON una matrice.
Per la matrice PRIMA allochi le righe POI, PER OGNI RIGA, allochi lo spazio per le colonne...tipo:

/*  righe (ogni elemento è un puntatore) */
mat1 = (int**)malloc( row1 * sizeof(int) );

/* Colonne */
for(i=0; i<row1; i++)
    mat1 = (int*)malloc( col1 * sizeof(int) );



Correggetemi se sto sbagliando qualcosa. E' vero che sto allocando in questo modo un array, ma in memoria una matrice viene comunque vista come un array di N elementi, per tale ragione si accede agli elementi dell'array in quel modo, ad esempio: *(mat1 + i*RIGA + j).

PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 12:16
Giovedì, 06/09/2018
Infatti ho scritto CONCETTUALE.
Ai fini pratici per questo esercizio non da problemi.

Un'altro errore, ma di DIMENTICANZA , è non eseguire i controlli sulle dimensioni delle due matrici (potrei cassare come parametri Stringhe, Numeri negativi...oppure semplicemente righe e colonne di matrici non moltiplicabili.
Queste non sono errori che precludono il funzionamento del programma in se, ma non lo rendono affidabile, tutto qui.

(P.s. hai dichiarato int main(....) è bene  far restituire un valore al main. )

Ultima modifica effettuata da Mikelius il 06/09/2018 alle 12:22
PM Quote
Avatar
comtel (Member)
Pro


Messaggi: 145
Iscritto: 08/04/2011

Segnala al moderatore
Postato alle 12:19
Giovedì, 06/09/2018
Testo quotato

Postato originariamente da Mikelius:

Infatti ho scritto CONCETTUALE.
Ai fini pratici per questo esercizio non da problemi.



Va bene, va bene.
Intanto ancora devo risolvere il problema del prodotto (ho anche provato con la soluzione di lumo, per quanto secondo i miei test non sia del tutto esatta), ma continuerò con l'esercizio sperando di trovarla successivamente.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 12:20
Giovedì, 06/09/2018
Non è un errore, è più confusione terminologica.
La matrice in matematica è una rappresentazione di una trasformazione lineare, in un programma si può rappresentare in diversi modi tra cui uno di questi è quello con un array ( e anche il più semplice secondo me).
La confusione sta nel fatto che anche in programmazione si dice matrice, ma in realtà si dovrebbe dire array multidimensionale lol

PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo