Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Validite d'un code de multiplication de matrices

13 réponses
Avatar
Bernard
Bonjour,

Je souhaiterais avoir votre avis sur les deux fonctions suivantes
réalisant la même fonction : une multiplication de matrices.

Concernant Multiplier_matrices, je pense que c'est une fonction
générique conforme à l'ISO C90 et qui peut multiplier deux matrices
(pour peu que le nombre de colonnes de la première corresponde au
nombre de lignes de la deuxième)

Par contre pour produit_matrice (qui ne multiplie que deux matrices
carrées), je suis un peu sceptique. L'idée est d'utiliser les nouvelles
fonctionnalités du C99 (à savoir pouvoir utiliser un tableau de taille
variable). A vrai dire je suis stupéfait que cette fonction compile et
renvoie le bon résultat (avec gcc 3.2).


A noter que si j'effectue la définition sous la nouvelle forme:
void produit_matrice(double mat_e1[dim][dim], double mat_e2[dim][dim],
double mat_s[dim][dim], int dim)
Cela ne compile même pas !

Donc voici mes questions :
1) Pourriez-vous me dire si Multiplier_matrices est bien conforme à
l'ISO C90
2) Pourriez-vous me dire si produit_matrice est bien conforme à l'ISO
C99 et m'expliquer pourquoi cela marche ? (si c'est juste une extension
de gcc par exemple ?)

Merci et voici le code :

#include <stdio.h>
#include <stdlib.h>

#define DIMENSION 10

void produit_matrice (mat_e1, mat_e2, mat_s, dim)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];
{
int i, j, k;

for (i = 0; i < dim; i++)
{
for (j = 0; j < dim; j++)
{
mat_s[i][j] = 0.;
for (k = 0; k < dim; k++)
{
mat_s[i][j] = mat_s[i][j] + mat_e1[i][k] * mat_e2[k][j];
}
}
}
}

void Multiplier_matrices (void *A, void *B, int Nblignes, int
Nbcolonnes, int DimMultiplication, void *X)
{
int i, j, k;
double produit;
double *Matrice_A = A;
double *Matrice_B = B;
double *Matrice_X = X;


for (i = 0; i < Nblignes; i++)
for (j = 0; j < Nbcolonnes; j++)
{
produit = 0;
for (k = 0; k < DimMultiplication; k++)
produit =
produit + Matrice_A[i * DimMultiplication +
k] * Matrice_B[k * Nbcolonnes + j];
Matrice_X[i * Nbcolonnes + j] = produit;
}
}


int main (void)
{
double A[DIMENSION][DIMENSION];
double B[DIMENSION][DIMENSION];
double C[DIMENSION][DIMENSION];

int i, j;

for (i = 0; i < DIMENSION; i++)
for (j = 0; j < DIMENSION; j++)
if (i == j)
A[i][j] = 1;
else
A[i][j] = 0;

for (i = 0; i < DIMENSION; i++)
for (j = 0; j < DIMENSION; j++)
B[i][j] = i + j;

produit_matrice (A, B, C, DIMENSION);
/*Multiplier_matrices(A, B, DIMENSION, DIMENSION, DIMENSION, C); */

for (i = 0; i < DIMENSION; i++)
{
for (j = 0; j < DIMENSION; j++)
printf ("%f ", C[i][j]);
printf ("\n");
}

return EXIT_SUCCESS;
}

10 réponses

1 2
Avatar
Nomak
Le 22/06/2004 à 19:58:58, Bernard a écrit:

Bonjour,


Bonjour,


printf ("%f ", C[i][j]);
^^ %2g


Un élément de réponse:

$ gcc-3.4.0 -W -Wall -stdÈ9 -pedantic mat.c
^^^
mat.c: In function `produit_matrice':
mat.c:8: attention : ISO C90 interdit le tableau « mat_e1 » de taille
variable
mat.c:8: attention : ISO C90 interdit le tableau « mat_e1 » de taille
variable
mat.c:8: attention : ISO C90 interdit le tableau « mat_e2 » de taille
variable
mat.c:8: attention : ISO C90 interdit le tableau « mat_e2 » de taille
variable
mat.c:8: attention : ISO C90 interdit le tableau « mat_s » de taille
variable
mat.c:8: attention : ISO C90 interdit le tableau « mat_s » de taille
variable


$ gcc-3.4.0 -W -Wall -stdÉ9 -pedantic mat.c
^^^

$ ./a.out
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10 11
3 4 5 6 7 8 9 10 11 12
4 5 6 7 8 9 10 11 12 13
5 6 7 8 9 10 11 12 13 14
6 7 8 9 10 11 12 13 14 15
7 8 9 10 11 12 13 14 15 16
8 9 10 11 12 13 14 15 16 17
9 10 11 12 13 14 15 16 17 18

extrait du man de gcc:

-std Determine the language standard. This option is currently only
supported when compiling C or C++. A value for this option must be
provided; possible values are

c89
iso9899:1990
ISO C90 (same as -ansi).

iso9899:199409
ISO C90 as modified in amendment 1.

c99
c9x
iso9899:1999
iso9899:199x
ISO C99. Note that this standard is not yet fully supported;
see <http://gcc.gnu.org/gcc-3.4/c99status.html> for more infor-
mation. The names c9x and iso9899:199x are deprecated.

gnu89
Default, ISO C90 plus GNU extensions (including some C99 fea-
tures).

gnu99
gnu9x
ISO C99 plus GNU extensions. When ISO C99 is fully implemented
in GCC, this will become the default. The name gnu9x is depre-
cated.

c++98
The 1998 ISO C++ standard plus amendments.

gnu++98
The same as -std=c++98 plus GNU extensions. This is the
default for C++ code.

Even when this option is not specified, you can still use some of
the features of newer standards in so far as they do not conflict
with previous C standards. For example, you may use "__restrict__"
even when -stdÉ9 is not specified.

The -std options specifying some version of ISO C have the same
effects as -ansi, except that features that were not in ISO C90 but
are in the specified version (for example, // comments and the
"inline" keyword in ISO C99) are not disabled.


Et à l'URL http://gcc.gnu.org/gcc-3.4/c99status.html, il y a:

variable-length arrays Broken


# The C99 semantics of variable length arrays (VLAs) are not fully
implemented by the existing GCC extension: the concept of variably modified
(VM) types, and the rules for what identifiers can be declared with VLA or
VM types, are not implemented (for example, GCC allows elements of VM type
in a structure with block scope); while the syntax for arrays to be declared
with [*] in parameter declarations is present, the semantics are not; and in
general the implementation of VLAs has not been checked against C99
requirements.


--
Nomak

Avatar
Nomak
Le 22/06/2004 à 19:58:58, Bernard a écrit:

[...]


Autre élément:

$ diff -u mat.c.orig mat.c
--- mat.c.orig 2004-06-22 20:55:02.967736447 +0200
+++ mat.c 2004-06-22 20:54:43.071064196 +0200
@@ -3,9 +3,8 @@

#define DIMENSION 10

-void produit_matrice (mat_e1, mat_e2, mat_s, dim)
- int dim;
- double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];
+void produit_matrice(int dim, double mat_e1[dim][dim], double
mat_e2[dim][dim],
+ double mat_s[dim][dim])
{
int i, j, k;

@@ -64,7 +63,7 @@
for (j = 0; j < DIMENSION; j++)
B[i][j] = i + j;

- produit_matrice (A, B, C, DIMENSION);
+ produit_matrice (DIMENSION, A, B, C);
/*Multiplier_matrices(A, B, DIMENSION, DIMENSION, DIMENSION, C);
*/

for (i = 0; i < DIMENSION; i++)

$ gcc-3.4.0 -W -Wall -stdÉ9 -pedantic mat.c

ça compile

et ta procédure Multiplier_matrices donne le bon résultat sur
l'exemple.


--
Nomak

Avatar
Bernard
On Tue, 22 Jun 2004 20:54:03 +0200, Nomak
wrote :

[...]


Autre élément:

$ diff -u mat.c.orig mat.c
--- mat.c.orig 2004-06-22 20:55:02.967736447 +0200
+++ mat.c 2004-06-22 20:54:43.071064196 +0200
@@ -3,9 +3,8 @@

#define DIMENSION 10

-void produit_matrice (mat_e1, mat_e2, mat_s, dim)
- int dim;
- double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];
+void produit_matrice(int dim, double mat_e1[dim][dim], double
mat_e2[dim][dim],
+ double mat_s[dim][dim])
{
int i, j, k;

@@ -64,7 +63,7 @@
for (j = 0; j < DIMENSION; j++)
B[i][j] = i + j;

- produit_matrice (A, B, C, DIMENSION);
+ produit_matrice (DIMENSION, A, B, C);
/*Multiplier_matrices(A, B, DIMENSION, DIMENSION, DIMENSION, C);
*/

for (i = 0; i < DIMENSION; i++)

$ gcc-3.4.0 -W -Wall -stdÉ9 -pedantic mat.c

ça compile

et ta procédure Multiplier_matrices donne le bon résultat sur
l'exemple.



Merci pour ces quelques précisions, cependant j'aurais aimé avoir l'avis
d'un expert sur ce forum pour valider ces deux fonctions. Je suis un peu
déçu de ne pas avoir eu plus de réponses mais bon ce que vous m'avez
donné n'est déjà pas si mal !

Merci encore !


Avatar
Jean-Noël Mégoz
"Bernard" a écrit dans le message de
news:
On Tue, 22 Jun 2004 20:54:03 +0200, Nomak

Merci pour ces quelques précisions, cependant j'aurais aimé avoir l'avis
d'un expert sur ce forum pour valider ces deux fonctions. Je suis un peu
déçu de ne pas avoir eu plus de réponses mais bon ce que vous m'avez
donné n'est déjà pas si mal !

Merci encore !


Ben t'es gourmand, toi ! Je trouve que la réponse de Nomak est déjà bien
supérieure à ce qu'un message en NG en droit d'attendre habituellement !

Perso, je n'y connais rien en C90, C99 et autres normes... Ce que je vais te
dire est donc peut être une ânerie. Dans ce cas, excuse-moi et passe vite à
autre chose !
Bref, pour moi, quand tu écris :

void produit_matrice(double mat_e1[dim][dim], double mat_e2[dim][dim],
double mat_s[dim][dim], int dim)

tu définis une fonction dont les 3 premiers paramètres sont des "double",
pas des tableaux ! La notation tableau[i][j] désigne un des *éléments* du
tableau, et pas son adresse !
D'ailleurs, quand je fais un copier/coller de ton code dans VC++, c'est ta
*première* fonction qui bloque :

void produit_matrice (mat_e1, mat_e2, mat_s, dim)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];

fait hurler le compilo :

C:toto.cpp(6) : error C2065: 'mat_e1' : undeclared identifier
C:toto.cpp(6) : error C2065: 'mat_e2' : undeclared identifier
C:toto.cpp(6) : error C2065: 'mat_s' : undeclared identifier
C:toto.cpp(6) : error C2065: 'dim' : undeclared identifier

A part ça, je ne vois pas ce qui te gène dans le reste du code. Pourquoi
es-tu étonné que "ça marche" ?

Avatar
Bernard
On Fri, 25 Jun 2004 00:43:51 +0200, "Jean-Noël Mégoz"

Merci pour ces quelques précisions, cependant j'aurais aimé avoir
l'avis d'un expert sur ce forum pour valider ces deux fonctions. Je
suis un peu déçu de ne pas avoir eu plus de réponses mais bon ce que
vous m'avez donné n'est déjà pas si mal !

Merci encore !


Ben t'es gourmand, toi ! Je trouve que la réponse de Nomak est déjà
bien supérieure à ce qu'un message en NG en droit d'attendre
habituellement !


Oui bon c'est vrai j'ai été un peu difficile...
Mes excuses à M. Nomak !

Perso, je n'y connais rien en C90, C99 et autres normes... Ce que je
vais te dire est donc peut être une ânerie. Dans ce cas, excuse-moi et
passe vite à autre chose !


Oups ! A la lecture de ce qui suit, tu débutes apparemment...

Bref, pour moi, quand tu écris :

void produit_matrice(double mat_e1[dim][dim], double
mat_e2[dim][dim],
double mat_s[dim][dim], int dim)

tu définis une fonction dont les 3 premiers paramètres sont des
"double", pas des tableaux ! La notation tableau[i][j] désigne un des
*éléments* du tableau, et pas son adresse !
D'ailleurs, quand je fais un copier/coller de ton code dans VC++,
c'est ta*première* fonction qui bloque :


Non quand tu déclares :
double A[4][5];
Tu ne déclares pas un double !!! Tu déclares un tableau !
On parle de déclaration là, pas d'instructions...


void produit_matrice (mat_e1, mat_e2, mat_s, dim)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];

fait hurler le compilo :

C:toto.cpp(6) : error C2065: 'mat_e1' : undeclared identifier
C:toto.cpp(6) : error C2065: 'mat_e2' : undeclared identifier
C:toto.cpp(6) : error C2065: 'mat_s' : undeclared identifier
C:toto.cpp(6) : error C2065: 'dim' : undeclared identifier


Ah ! Etrange que cela passe avec gcc et pas avec VC++.
Est-ce qu'il n'y a pas une option quelque part qui interdit l'usage de
l'ancienne forme de déclaration ?

A part ça, je ne vois pas ce qui te gène dans le reste du code.
Pourquoi es-tu étonné que "ça marche" ?


Disons qu'en C90 ce que j'ai fait est totalemen interdit et je ne savais
pas qu'en C99 c'était autorisé...


Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', "Jean-Noël Mégoz" wrote:

Perso, je n'y connais rien en C90, C99 et autres normes... Ce que je


Ce qui fait de toi un expert en C...

vais te dire est donc peut être une ânerie. Dans ce cas, excuse-moi et
passe vite à autre chose !
Bref, pour moi, quand tu écris :

void produit_matrice(double mat_e1[dim][dim], double
mat_e2[dim][dim],
double mat_s[dim][dim], int dim)

tu définis une fonction dont les 3 premiers paramètres sont des
"double", pas des tableaux !


C'est faux.

La notation tableau[i][j] désigne un des
*éléments* du tableau, et pas son adresse !


Si, justement, dans le cadre d'un paramètre de fonction. Par contre, ce qui
ne va pas, c'est qu'il s'agit de VLA (C99), et que la taille est passée
*après* la définition des pointeurs.

C'est pourquoi il faut modifier l'ordre des paramètres ainsi :

void produit_matrice (int dim
, double mat_e1[dim][dim]
, double mat_e2[dim][dim]
, double mat_s[dim][dim])

D'ailleurs, quand je fais un copier/coller de ton code dans VC++, c'est
ta *première* fonction qui bloque :

void produit_matrice (mat_e1, mat_e2, mat_s, dim)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];


Normal, ce vieux code est incohérent :

void produit_matrice (dim, mat_e1, mat_e2, mat_s)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];

De plus, VC++ n'est pas C99, mais C90 (pas de VLA).

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Bernard
On 25 Jun 2004 12:46:56 GMT, Emmanuel Delahaye
wrote :

Si, justement, dans le cadre d'un paramètre de fonction. Par contre,
ce qui ne va pas, c'est qu'il s'agit de VLA (C99), et que la taille
est passée *après* la définition des pointeurs.

C'est pourquoi il faut modifier l'ordre des paramètres ainsi :

void produit_matrice (int dim
, double mat_e1[dim][dim]
, double mat_e2[dim][dim]
, double mat_s[dim][dim])


Oui c'est bien ce que m'avait indiqué M. Nomak.


D'ailleurs, quand je fais un copier/coller de ton code dans VC++,
c'est ta *première* fonction qui bloque :

void produit_matrice (mat_e1, mat_e2, mat_s, dim)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];


Normal, ce vieux code est incohérent :

void produit_matrice (dim, mat_e1, mat_e2, mat_s)
int dim;
double mat_e1[dim][dim], mat_e2[dim][dim], mat_s[dim][dim];



Le code 'incohérent' est accepté par gcc (mais pas si on utilise la
nouvelle forme de déclaration des paramètres).
Donc je peux en déduire que c'est bien une erreur du compilateur
(j'ai normalement désactivé les extensions gcc et demandé du code ISO) ?

D'autre part je croyais que les VLA c'étaient pour du code de ce type :
void toto(int N)
{
double A[N][N];
}

Mais je ne savais pas que l'on pouvait aussi faire :
void toto(int N, double A[N][N])
{
...
}

Car dans ce cas il me semble que suivant N le type lui-même de A est
différent non ?
On obtient donc une sorte de fonction avec paramètre de type
dynamique (et sans passer par des void *) !
C'est vraiment pas mal du tout et je ne savais pas que le C99 apportait
de telles fonctionnalités !


Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Bernard wrote:

Mais je ne savais pas que l'on pouvait aussi faire :
void toto(int N, double A[N][N])
{
...
}

Car dans ce cas il me semble que suivant N le type lui-même de A est
différent non ?
On obtient donc une sorte de fonction avec paramètre de type
dynamique (et sans passer par des void *) !
C'est vraiment pas mal du tout et je ne savais pas que le C99 apportait
de telles fonctionnalités !


J'ai quand même un doute. Je ne suis pas expert de C99. Attendons l'avis des
vrais spécialistes.

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?libÉ9
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Bernard
On 25 Jun 2004 13:56:34 GMT, Emmanuel Delahaye
wrote :

Mais je ne savais pas que l'on pouvait aussi faire :
void toto(int N, double A[N][N])
{
...
}

Car dans ce cas il me semble que suivant N le type lui-même de A est
différent non ?
On obtient donc une sorte de fonction avec paramètre de type
dynamique (et sans passer par des void *) !
C'est vraiment pas mal du tout et je ne savais pas que le C99
apportait de telles fonctionnalités !


J'ai quand même un doute. Je ne suis pas expert de C99. Attendons
l'avis des vrais spécialistes.



Dans la réponse que me fait M. Nomak :

# The C99 semantics of variable length arrays (VLAs) are not fully
implemented by the existing GCC extension: the concept of variably
modified (VM) types, and the rules for what identifiers can be declared
with VLA or VM types, are not implemented (for example, GCC allows
elements of VM type in a structure with block scope); while the syntax
for arrays to be declared with [*] in parameter declarations is present,
the semantics are not; and in general the implementation of VLAs has not
been checked against C99 requirements.

Il parle de type 'Variably Modified', c'est peut-être de ça qu'il s'agit
?

En tout cas j'ai aussi posé la question sur comp.lang.c sans aucun
succès. On me répond juste que 'ça passe' la compilation gcc avec
l'option -stdÉ9 mais ce n'est pas vraiment ni un argument ni une
explication...
Donc pour l'instant je reste un peu sceptique aussi...


Avatar
Richard Delorme
In 'fr.comp.lang.c', Bernard wrote:


Mais je ne savais pas que l'on pouvait aussi faire :
void toto(int N, double A[N][N])
{
...
}

Car dans ce cas il me semble que suivant N le type lui-même de A est
différent non ?
On obtient donc une sorte de fonction avec paramètre de type
dynamique (et sans passer par des void *) !
C'est vraiment pas mal du tout et je ne savais pas que le C99 apportait
de telles fonctionnalités !



J'ai quand même un doute. Je ne suis pas expert de C99. Attendons l'avis des
vrais spécialistes.



La norme du langage donne un exemple (§ 6.7.5.2, verset 10), qualifié de
valide, très semblable:
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA
{
}

--
Richard


1 2