vermaccio
28-03-2006, 19:45
a chi servisse ecco TRE funzioni che fanno la stessa cosa, compreso un esempio di test (usato matlab e matrici 4X4).
Lo scopo di queste funzioni è poter moltiplicare due matrici di grandezza "qualsiasi" (leggi nota in fondo) senza dover scrivere una funzione diversa se cambia la grandezza della matrice. non usando il sistema di puntatori che abbiamo implementato si dichiara nella intestazione della funione quante colonne ha la matrice e quindi non si può usare per una matrice con numero di colonne diverso. Invece con queste due function (identiche per risultati ma diverse per scrittura) basta passare le due matrici di input, il nome della matrice di output e le dimensioni di esse.
1
listato c++ di vermaccio
(per vedere tutto il suo sviluppo vedere
http://www.hwupgrade.it/forum/showpost.php?p=11809602&postcount=33
Ringrazio "andbin": senza la sua gentilezza, la sua pazienza e le sue infinite spiegazioni illuminanti non avrei mai potuto capire i puntatori.
Il cuore dell'algoritmo "puntatori" lo ha creato lui. Io l'ho applicato al caso del prodotto tra matrici.)
#include<stdio.h>
#include <math.h>
double A[2][2]= { {1, 2},{3,4} };
double B[2][2]= { {5,6},{7,-8} };
double C[4][3]= { {1, -2, 3},{-5, 0, 7},{-2, -1, 5},{3, 0, -1} };
double D[3][4]= { {1, 2, 3, 4},{5, 6, 7, 8},{-2, 1, -5, 12} };
double AB[2][2];
double CD[4][4];
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//funzione prodotto di due matrici XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void prodottomatrici(double *matrA, int nrigA, int ncolA, double *matrB, int nrigB, int ncolB, double *matrC, int nrigC, int ncolC) {
//i=righeA
//j=colonneB
//k=colonneA=righeB !!!!!!! se colonneA diverso da righeB si ha errore
int i, j, k; //variabili locali
double elemA, elemB, elemC; //variabili locali
for (i=0; i<nrigA; i++){ //scorro riga di matrice risultato
for (j=0; j<ncolB; j++){ //scorro colonna di matrice risultato
elemC=0; // sarebbe la matC[i][j]=0;
for (k=0; k<ncolA; k++){ //oppure k<nrigB visto che ncolA=nrigB
elemA = *(matrA + i * ncolA + k); //sarebbe la matA[i][k]
elemB = *(matrB + k * ncolB + j); //sarebbe la matB[k][j]
elemC = elemC+elemA*elemB; //sarebbe la matC[i][j]=matC[i][j]+matA[i][k]*matB[k][j];
//test=A[i][k]*B[k][j];
//printf("%g\n", test );
}
*(matrC + i * ncolC + j) = elemC;//ora assegno il risultato "elemC" alla matrice di uscita assegnando al puntatore
//adatto relativo alla giusta cella della matrice quel valore "elemC"
//printf("%g\n", matC[i][j] );
}
}
}
//--------------------
void main(void)
{
//notare gli [0][0] perchè sto passando i puntatori alprimo elemento della matrice
prodottomatrici (&A[0][0], 2, 2, &B[0][0], 2, 2, &AB[0][0], 2, 2);
printf("elemento [1][1] matrice prodotto A*B: %g\n", AB[0][0] );
printf("elemento [1][2] matrice prodotto A*B: %g\n", AB[0][1] );
printf("elemento [2][1] matrice prodotto A*B: %g\n", AB[1][0] );
printf("elemento [2][2] matrice prodotto A*B: %g\n", AB[1][1] );
printf("-------------------------- \n");
//notare gli [0][0] perchè sto passando i puntatori alprimo elemento della matrice
prodottomatrici (&C[0][0], 4, 3, &D[0][0], 3, 4, &CD[0][0], 4, 4);
printf("elemento [1][1] matrice prodotto C*D: %g\n", CD[0][0] );
printf("elemento [1][2] matrice prodotto C*D: %g\n", CD[0][1] );
printf("elemento [1][3] matrice prodotto C*D: %g\n", CD[0][2] );
printf("elemento [1][4] matrice prodotto C*D: %g\n", CD[0][3] );
printf("elemento [2][1] matrice prodotto C*D: %g\n", CD[1][0] );
printf("elemento [2][2] matrice prodotto C*D: %g\n", CD[1][1] );
printf("elemento [2][3] matrice prodotto C*D: %g\n", CD[1][2] );
printf("elemento [2][4] matrice prodotto C*D: %g\n", CD[1][3] );
printf("elemento [3][1] matrice prodotto C*D: %g\n", CD[2][0] );
printf("elemento [3][2] matrice prodotto C*D: %g\n", CD[2][1] );
printf("elemento [3][3] matrice prodotto C*D: %g\n", CD[2][2] );
printf("elemento [3][4] matrice prodotto C*D: %g\n", CD[2][3] );
printf("elemento [4][1] matrice prodotto C*D: %g\n", CD[3][0] );
printf("elemento [4][2] matrice prodotto C*D: %g\n", CD[3][1] );
printf("elemento [4][3] matrice prodotto C*D: %g\n", CD[3][2] );
printf("elemento [4][4] matrice prodotto C*D: %g\n", CD[3][3] );
}
/*risultati matlab
AB =
19 -10
43 -14
risultato c++: OK
CD =
-15 -7 -26 24
-19 -3 -50 64
-17 -5 -38 44
5 5 14 0
risultato c++: OK
*/
2
Questa invece è la soluzione di andbin, soluzione contenente più sottofunzioni sepratae per fare i vari passaggi.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
double *array;
int rows;
int columns;
} MATRIX_2D, *PMATRIX_2D;
/******************************************************************************/
/* FUNZIONI GENERICHE DI GESTIONE MATRICI */
/******************************************************************************/
double Matrix2D_GetValue (PMATRIX_2D pmatrix, int r, int c)
{
return *(pmatrix->array + r * pmatrix->columns + c);
}
void Matrix2D_SetValue (PMATRIX_2D pmatrix, int r, int c, double value)
{
*(pmatrix->array + r * pmatrix->columns + c) = value;
}
void Matrix2D_AddValue (PMATRIX_2D pmatrix, int r, int c, double value)
{
*(pmatrix->array + r * pmatrix->columns + c) += value;
}
int Matrix2D_Product (PMATRIX_2D pmatrix_a, PMATRIX_2D pmatrix_b, PMATRIX_2D pmatrix_out)
{
int rows, columns, r, c, i;
if (pmatrix_a->columns != pmatrix_b->rows)
return 0; /* Errore, matrici non compatibili! */
rows = pmatrix_a->rows;
columns = pmatrix_b->columns;
/* Allocazione matrice del prodotto */
pmatrix_out->array = (double*) malloc (rows * columns * sizeof (double));
pmatrix_out->rows = rows;
pmatrix_out->columns = columns;
for (r = 0; r < rows; r++)
{
for (c = 0; c < columns; c++)
{
Matrix2D_SetValue (pmatrix_out, r, c, 0.0);
for (i = 0; i < pmatrix_a->columns; i++)
{
Matrix2D_AddValue (pmatrix_out, r, c,
Matrix2D_GetValue (pmatrix_a, r, i) *
Matrix2D_GetValue (pmatrix_b, i, c));
}
}
}
return 1; /* Successo */
}
void Matrix2D_Free (PMATRIX_2D pmatrix)
{
free (pmatrix->array);
}
void Matrix2D_Print (PMATRIX_2D pmatrix)
{
int r, c;
for (r = 0; r < pmatrix->rows; r++)
{
for (c = 0; c < pmatrix->columns; c++)
{
if (c > 0)
printf (" ");
printf ("%9.3f", Matrix2D_GetValue (pmatrix, r, c));
}
printf ("\n");
}
}
/******************************************************************************/
/* MAIN */
/******************************************************************************/
double a[4][3]= { {1, -2, 3}, {-5, 0, 7}, {-2, -1, 5}, {3, 0, -1} };
double b[3][4]= { {1, 2, 3, 4}, {5, 6, 7, 8}, {-2, 1, -5, 12} };
int main (void)
{
MATRIX_2D matrix_a = { &a[0][0], 4, 3 };
MATRIX_2D matrix_b = { &b[0][0], 3, 4 };
MATRIX_2D matrix_prod;
if (Matrix2D_Product (&matrix_a, &matrix_b, &matrix_prod) != 0)
{
printf ("Matrice A\n");
Matrix2D_Print (&matrix_a);
printf ("\n");
printf ("Matrice B\n");
Matrix2D_Print (&matrix_b);
printf ("\n");
printf ("Matrice Prodotto\n");
Matrix2D_Print (&matrix_prod);
Matrix2D_Free (&matrix_prod);
}
return 0;
}
3
Listato di sottovento che, però, prevede prima una linearizzazione delle matrici ovvero una matrice A[m][n] (=array bidimensionale) deve essere prima trasformata in vettore monodimensionale A[m*n]
esempio
A[4][3] --> A[12]
e ala funzione gli passi in input A[12] e non più A[4][3].
int mult(double *matrA, int rowsA, int colsA,
double *matrB, int rowsB, int colsB,
double *matrC, int rowsC, int colsC)
{
int i, h, k; // counters
double elemC; // Temporary variables for calculation
// These are pointers to the corresponding current matrix' element
double *p2a, *p2b, *p2c;
// Check for right sizes
if (rowsA != rowsC ||
colsB != colsC ||
colsA != rowsB)
{
// Cannot perform this operation. Wrong sizes
return -1;
}
p2c = matrC;
for (h = 0; h < rowsA; h++)
{
for (i = 0; i < colsB; i++)
{
p2a = matrA + h * colsA;
p2b = matrB + i;
elemC = 0.0;
for (k = 0; k < colsA; k++)
{
elemC += *p2a++ * *p2b;
p2b += colsB;
}
*p2c++ = elemC;
}
}
return 0;
}
TEST:
con matlab (un programma matematico che esegue questi calcoli matriciali senza fatica) ho fatto i conti ed abbiamo verificato che i due programmi dessero lo stesso risultato. perfetto. funzionano.
Matrice A
1.000 -2.000 3.000
-5.000 0.000 7.000
-2.000 -1.000 5.000
3.000 0.000 -1.000
Matrice B
1.000 2.000 3.000 4.000
5.000 6.000 7.000 8.000
-2.000 1.000 -5.000 12.000
Matrice Prodotto A*B calcolata dai programmi
-15.000 -7.000 -26.000 24.000
-19.000 -3.000 -50.000 64.000
-17.000 -5.000 -38.000 44.000
5.000 5.000 14.000 0.000
OK!
i programmi funzionano!
essendo molti cicli for anndati e molte sommatorie e prodotti, se funziona con una matrice 4X4 è logico supporre che funzioni swempre. comunque se si usa il prgramma per fare calcoli grafici (matrici roto-traslazionali) di solito si usano proprio matrici 4X4
nota finale:
le dimensioni delle matrici da moltiplicare NON devono essere casuali.
se si hanno due matrici
A[a][b]
B[m][n]
per moltiplicare A*B
DEVE essere b=m
e la matrice che si ottiene è
C[a][n]=A*B
B*A=D[m][b] ma deve essere n=a
logicamente B*A è DIVERSO da A*B
(in calcolo matriciale NON vale la regola della matematica che due numeri moltiplicati danno lo stesso risultato se scambiati tra loro es: 2*3=3*2). quindi quando usate la funzione occhio a che matrice inseriote per prima e quale per seconda in input!!!!
Lo scopo di queste funzioni è poter moltiplicare due matrici di grandezza "qualsiasi" (leggi nota in fondo) senza dover scrivere una funzione diversa se cambia la grandezza della matrice. non usando il sistema di puntatori che abbiamo implementato si dichiara nella intestazione della funione quante colonne ha la matrice e quindi non si può usare per una matrice con numero di colonne diverso. Invece con queste due function (identiche per risultati ma diverse per scrittura) basta passare le due matrici di input, il nome della matrice di output e le dimensioni di esse.
1
listato c++ di vermaccio
(per vedere tutto il suo sviluppo vedere
http://www.hwupgrade.it/forum/showpost.php?p=11809602&postcount=33
Ringrazio "andbin": senza la sua gentilezza, la sua pazienza e le sue infinite spiegazioni illuminanti non avrei mai potuto capire i puntatori.
Il cuore dell'algoritmo "puntatori" lo ha creato lui. Io l'ho applicato al caso del prodotto tra matrici.)
#include<stdio.h>
#include <math.h>
double A[2][2]= { {1, 2},{3,4} };
double B[2][2]= { {5,6},{7,-8} };
double C[4][3]= { {1, -2, 3},{-5, 0, 7},{-2, -1, 5},{3, 0, -1} };
double D[3][4]= { {1, 2, 3, 4},{5, 6, 7, 8},{-2, 1, -5, 12} };
double AB[2][2];
double CD[4][4];
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//funzione prodotto di due matrici XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void prodottomatrici(double *matrA, int nrigA, int ncolA, double *matrB, int nrigB, int ncolB, double *matrC, int nrigC, int ncolC) {
//i=righeA
//j=colonneB
//k=colonneA=righeB !!!!!!! se colonneA diverso da righeB si ha errore
int i, j, k; //variabili locali
double elemA, elemB, elemC; //variabili locali
for (i=0; i<nrigA; i++){ //scorro riga di matrice risultato
for (j=0; j<ncolB; j++){ //scorro colonna di matrice risultato
elemC=0; // sarebbe la matC[i][j]=0;
for (k=0; k<ncolA; k++){ //oppure k<nrigB visto che ncolA=nrigB
elemA = *(matrA + i * ncolA + k); //sarebbe la matA[i][k]
elemB = *(matrB + k * ncolB + j); //sarebbe la matB[k][j]
elemC = elemC+elemA*elemB; //sarebbe la matC[i][j]=matC[i][j]+matA[i][k]*matB[k][j];
//test=A[i][k]*B[k][j];
//printf("%g\n", test );
}
*(matrC + i * ncolC + j) = elemC;//ora assegno il risultato "elemC" alla matrice di uscita assegnando al puntatore
//adatto relativo alla giusta cella della matrice quel valore "elemC"
//printf("%g\n", matC[i][j] );
}
}
}
//--------------------
void main(void)
{
//notare gli [0][0] perchè sto passando i puntatori alprimo elemento della matrice
prodottomatrici (&A[0][0], 2, 2, &B[0][0], 2, 2, &AB[0][0], 2, 2);
printf("elemento [1][1] matrice prodotto A*B: %g\n", AB[0][0] );
printf("elemento [1][2] matrice prodotto A*B: %g\n", AB[0][1] );
printf("elemento [2][1] matrice prodotto A*B: %g\n", AB[1][0] );
printf("elemento [2][2] matrice prodotto A*B: %g\n", AB[1][1] );
printf("-------------------------- \n");
//notare gli [0][0] perchè sto passando i puntatori alprimo elemento della matrice
prodottomatrici (&C[0][0], 4, 3, &D[0][0], 3, 4, &CD[0][0], 4, 4);
printf("elemento [1][1] matrice prodotto C*D: %g\n", CD[0][0] );
printf("elemento [1][2] matrice prodotto C*D: %g\n", CD[0][1] );
printf("elemento [1][3] matrice prodotto C*D: %g\n", CD[0][2] );
printf("elemento [1][4] matrice prodotto C*D: %g\n", CD[0][3] );
printf("elemento [2][1] matrice prodotto C*D: %g\n", CD[1][0] );
printf("elemento [2][2] matrice prodotto C*D: %g\n", CD[1][1] );
printf("elemento [2][3] matrice prodotto C*D: %g\n", CD[1][2] );
printf("elemento [2][4] matrice prodotto C*D: %g\n", CD[1][3] );
printf("elemento [3][1] matrice prodotto C*D: %g\n", CD[2][0] );
printf("elemento [3][2] matrice prodotto C*D: %g\n", CD[2][1] );
printf("elemento [3][3] matrice prodotto C*D: %g\n", CD[2][2] );
printf("elemento [3][4] matrice prodotto C*D: %g\n", CD[2][3] );
printf("elemento [4][1] matrice prodotto C*D: %g\n", CD[3][0] );
printf("elemento [4][2] matrice prodotto C*D: %g\n", CD[3][1] );
printf("elemento [4][3] matrice prodotto C*D: %g\n", CD[3][2] );
printf("elemento [4][4] matrice prodotto C*D: %g\n", CD[3][3] );
}
/*risultati matlab
AB =
19 -10
43 -14
risultato c++: OK
CD =
-15 -7 -26 24
-19 -3 -50 64
-17 -5 -38 44
5 5 14 0
risultato c++: OK
*/
2
Questa invece è la soluzione di andbin, soluzione contenente più sottofunzioni sepratae per fare i vari passaggi.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
double *array;
int rows;
int columns;
} MATRIX_2D, *PMATRIX_2D;
/******************************************************************************/
/* FUNZIONI GENERICHE DI GESTIONE MATRICI */
/******************************************************************************/
double Matrix2D_GetValue (PMATRIX_2D pmatrix, int r, int c)
{
return *(pmatrix->array + r * pmatrix->columns + c);
}
void Matrix2D_SetValue (PMATRIX_2D pmatrix, int r, int c, double value)
{
*(pmatrix->array + r * pmatrix->columns + c) = value;
}
void Matrix2D_AddValue (PMATRIX_2D pmatrix, int r, int c, double value)
{
*(pmatrix->array + r * pmatrix->columns + c) += value;
}
int Matrix2D_Product (PMATRIX_2D pmatrix_a, PMATRIX_2D pmatrix_b, PMATRIX_2D pmatrix_out)
{
int rows, columns, r, c, i;
if (pmatrix_a->columns != pmatrix_b->rows)
return 0; /* Errore, matrici non compatibili! */
rows = pmatrix_a->rows;
columns = pmatrix_b->columns;
/* Allocazione matrice del prodotto */
pmatrix_out->array = (double*) malloc (rows * columns * sizeof (double));
pmatrix_out->rows = rows;
pmatrix_out->columns = columns;
for (r = 0; r < rows; r++)
{
for (c = 0; c < columns; c++)
{
Matrix2D_SetValue (pmatrix_out, r, c, 0.0);
for (i = 0; i < pmatrix_a->columns; i++)
{
Matrix2D_AddValue (pmatrix_out, r, c,
Matrix2D_GetValue (pmatrix_a, r, i) *
Matrix2D_GetValue (pmatrix_b, i, c));
}
}
}
return 1; /* Successo */
}
void Matrix2D_Free (PMATRIX_2D pmatrix)
{
free (pmatrix->array);
}
void Matrix2D_Print (PMATRIX_2D pmatrix)
{
int r, c;
for (r = 0; r < pmatrix->rows; r++)
{
for (c = 0; c < pmatrix->columns; c++)
{
if (c > 0)
printf (" ");
printf ("%9.3f", Matrix2D_GetValue (pmatrix, r, c));
}
printf ("\n");
}
}
/******************************************************************************/
/* MAIN */
/******************************************************************************/
double a[4][3]= { {1, -2, 3}, {-5, 0, 7}, {-2, -1, 5}, {3, 0, -1} };
double b[3][4]= { {1, 2, 3, 4}, {5, 6, 7, 8}, {-2, 1, -5, 12} };
int main (void)
{
MATRIX_2D matrix_a = { &a[0][0], 4, 3 };
MATRIX_2D matrix_b = { &b[0][0], 3, 4 };
MATRIX_2D matrix_prod;
if (Matrix2D_Product (&matrix_a, &matrix_b, &matrix_prod) != 0)
{
printf ("Matrice A\n");
Matrix2D_Print (&matrix_a);
printf ("\n");
printf ("Matrice B\n");
Matrix2D_Print (&matrix_b);
printf ("\n");
printf ("Matrice Prodotto\n");
Matrix2D_Print (&matrix_prod);
Matrix2D_Free (&matrix_prod);
}
return 0;
}
3
Listato di sottovento che, però, prevede prima una linearizzazione delle matrici ovvero una matrice A[m][n] (=array bidimensionale) deve essere prima trasformata in vettore monodimensionale A[m*n]
esempio
A[4][3] --> A[12]
e ala funzione gli passi in input A[12] e non più A[4][3].
int mult(double *matrA, int rowsA, int colsA,
double *matrB, int rowsB, int colsB,
double *matrC, int rowsC, int colsC)
{
int i, h, k; // counters
double elemC; // Temporary variables for calculation
// These are pointers to the corresponding current matrix' element
double *p2a, *p2b, *p2c;
// Check for right sizes
if (rowsA != rowsC ||
colsB != colsC ||
colsA != rowsB)
{
// Cannot perform this operation. Wrong sizes
return -1;
}
p2c = matrC;
for (h = 0; h < rowsA; h++)
{
for (i = 0; i < colsB; i++)
{
p2a = matrA + h * colsA;
p2b = matrB + i;
elemC = 0.0;
for (k = 0; k < colsA; k++)
{
elemC += *p2a++ * *p2b;
p2b += colsB;
}
*p2c++ = elemC;
}
}
return 0;
}
TEST:
con matlab (un programma matematico che esegue questi calcoli matriciali senza fatica) ho fatto i conti ed abbiamo verificato che i due programmi dessero lo stesso risultato. perfetto. funzionano.
Matrice A
1.000 -2.000 3.000
-5.000 0.000 7.000
-2.000 -1.000 5.000
3.000 0.000 -1.000
Matrice B
1.000 2.000 3.000 4.000
5.000 6.000 7.000 8.000
-2.000 1.000 -5.000 12.000
Matrice Prodotto A*B calcolata dai programmi
-15.000 -7.000 -26.000 24.000
-19.000 -3.000 -50.000 64.000
-17.000 -5.000 -38.000 44.000
5.000 5.000 14.000 0.000
OK!
i programmi funzionano!
essendo molti cicli for anndati e molte sommatorie e prodotti, se funziona con una matrice 4X4 è logico supporre che funzioni swempre. comunque se si usa il prgramma per fare calcoli grafici (matrici roto-traslazionali) di solito si usano proprio matrici 4X4
nota finale:
le dimensioni delle matrici da moltiplicare NON devono essere casuali.
se si hanno due matrici
A[a][b]
B[m][n]
per moltiplicare A*B
DEVE essere b=m
e la matrice che si ottiene è
C[a][n]=A*B
B*A=D[m][b] ma deve essere n=a
logicamente B*A è DIVERSO da A*B
(in calcolo matriciale NON vale la regola della matematica che due numeri moltiplicati danno lo stesso risultato se scambiati tra loro es: 2*3=3*2). quindi quando usate la funzione occhio a che matrice inseriote per prima e quale per seconda in input!!!!