Partage
  • Partager sur Facebook
  • Partager sur Twitter

Opération matricielle

    6 octobre 2016 à 16:22:38

    Bonjour, 

    J'ai un petit soucis concernant une fonction de déterminant, quelqu'un sait d'où peut provenir l'erreur ? Je suis pour l'instant dans une phase d'apprentissage du langage C ! 

    int determinant(struct matrix *A)
    {
        int j, i, k, l;
        int p; 
        int d = 1;
        struct matrix *B;
        B = copie_matrice(A);
        for (j = 0; j < B->nc-1; j++)
        {
            p = j; 
            for (i = j+1; i < B->nr; i++)
            {
                if (B->data[i][j] > B->data[p][j])
                    p = i;
            }
            if (p != j)
            {
                float *tmp;
                d *= -1;
                tmp = B->data[j];
                B->data[j] = B->data[p];
                B->data[p] = tmp;
            }
            for (i = j+1; i < B->nr; i++)
            {
    			for (k = 0; k < B->nc; k++)
    			{
    				float * test = mult_scalaire(B->data[j], (B->data[i][j] / B->data[j][j]));
    				B->data[i][k] = B->data[i][k] - test[k];
    			}
            }
        }
        for (l = 0; l < B->nr; l++)
            d = d * B->data[l][l];
        return d;

    Il me renvoie sans arrêt la valeur de d = 0 ! 

    Merci d'avance.

    • Partager sur Facebook
    • Partager sur Twitter
      6 octobre 2016 à 16:29:27

      Bonjour,

      peut-etre parce que ta fonction retourne un int au lieu de float...

      Faudrait voir la tête de la matrice en entrée.

      • Partager sur Facebook
      • Partager sur Twitter
        6 octobre 2016 à 16:39:28

        La matrice en entrée est du type : A = { {1,1,2}, {0,1,1}, {0,0,7}}.

        Après modification, le problème ne viendrait pas de là. 

        -
        Edité par TLHD 6 octobre 2016 à 16:42:41

        • Partager sur Facebook
        • Partager sur Twitter
          6 octobre 2016 à 17:17:14

          Soit c'est un problème d'algorithme, et c'est à toi de le trouver (pas nous, on ne le connaît pas ─ on peut difficilement le deviner à partir du code car il n'y a aucun commentaire), soit c'est un problème de programmation, mais pour le trouver il faut trouver l'endroit où se situe l'erreur.

          Calcule le déterminant à la main (avec la même méthode que dans le programme) et fait afficher (par des printf) les calculs intermédiaires. En comparant, tu verras aussitôt où est l'erreur.

          -
          Edité par robun 6 octobre 2016 à 17:23:58

          • Partager sur Facebook
          • Partager sur Twitter
            6 octobre 2016 à 17:46:13

            L'algorithme est juste, dans un autre langage il fonctionne parfaitement bien. 

            L'implémentation en C a donc un soucis, cette méthode permet de calculer un déterminant de matrice en utilisant une partie du pivot de Gauss.

            • Partager sur Facebook
            • Partager sur Twitter
              6 octobre 2016 à 18:43:10

              Ça n'empêche pas d'essayer de comparer le déroulement du programme avec un déroulement à la main ─ ou avec le programme identique écrit dans l'autre langage, tiens, justement.

              (Il y a deux semaines j'avais programmé une résolution de système linéaire par pivot (avec une structure modélisant des fractions) et il choisissait toujours les pivots dans l'ordre : 1, 2, 3... alors que j'avais écrit une fonction pour qu'il choisisse les pivots plus judicieusement, eh bien j'ai mis des printf dans la fonction pour voir ce qu'il faisait exactement et j'ai trouvé immédiatement l'erreur (une erreur de programmation idiote). Je suis persuadé qu'examiner le code aurait été plus long ─ surtout que, pour moi, ce n'était pas une erreur avant de constater de visu qu'il ne faisait pas ce que je croyais).)

              • Partager sur Facebook
              • Partager sur Twitter
                6 octobre 2016 à 22:29:46

                Bonsoir,

                En tout cas, j'ai l'impression de voir plein de fuites mémoires (B, test)....

                On peut avoir un code complet?

                • Partager sur Facebook
                • Partager sur Twitter
                ** La doc, c'est comme le PQ: ça sert à se démerder tout seul **
                  7 octobre 2016 à 1:42:59

                  Bonsoir, 

                  Complet je ne pourrais malheureusement pas, mais quelles fonctions veux-tu que je poste ? 

                  @robun, j'ai suivi ton conseil et appliqué ta méthode et à priori ça serait à cette endroit que ça cale : 

                  float * test = mult_scalaire(B->data[j], (B->data[i][j] / B->data[j][j]));
                  B->data[i][k] = B->data[i][k] - test[k];

                  Mais après relecture, ça ne m'a pas choqué..

                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 octobre 2016 à 3:26:42

                    Je suis prêt à t'aider parce que ça m'intéresse (figure-toi que le calcul de déterminant est un de mes prochains projets et j'avais besoin de réviser l'algorithme, donc tu tombes bien...), et puisque personne n'a détecté d'erreur, je soupçonne que c'est une erreur de maths et non de C. Voici une recopie de ton code, en ayant ajouté plein de commentaires pour bien comprendre ce qu'il fait (oui, je n'ai pas lésiné...) N'hésite pas à me corriger si j'ai mal interprété certaines lignes).

                    Remarque : j'ai bien sûr remplacé 'int' par 'float' (tu as dit que l'erreur persistait malgré cette correction). J'ai aussi déplacé les déclarations de p et k dans les blocs où ils sont utiles par pur réflexe maniaque (j'aime bien que les déclarations des variables soient proches de là où elles sont utilisées vu que j'y mets des commentaires). 

                    float determinant(struct matrix *A)
                    {
                        int i;              // numéro de ligne, entre 0 et A->nr-1
                        int j;              // numéro de colonne, entre 0 et A->nl-1
                        int l;              // indice des éléments diagonaux (sert à la fin)
                        float d = 1.0F;     // variable contenant la valeur à retourner
                        struct matrix *B;   // recopie de A, nécessaire pour ne pas modifier A
                        B = copie_matrice(A);
                    
                        /* Déroulement du pivot */
                        // Méthode : pour chaque colonne j, on choisit un pivot à la ligne p.
                        // Si cette ligne n'est pas la ligne j (donc si le pivot n'est pas sur
                        // la diagonale), on permute les lignes j et p. Ainsi, à la fin du
                        // traitement de la colonne j, les pivots ont été ramenés aux j premières
                        // lignes.
                        for (j = 0; j < B->nc-1; j++)   // on choisira un pivot à chaque colonne (sauf la dernière)
                        {
                            /* Recherche du pivot de la colonne j */
                            // On le recherche dans les lignes situées à partir de j, car les
                            // pivots précédents ont été ramenées aux lignes 0 à j-1.
                            int p = j;  // numéro de ligne du pivot
                            for (i = j+1; i < B->nr; i++)   //
                            {   // On regarde si un meilleur pivot existe dans les lignes suivantes
                                if (B->data[i][j] > B->data[p][j])  // J'AURAIS MIS UNE VALEUR ABSOLUE
                                    p = i;
                            }
                            if (p != j) // On permute les lignes j et p
                            {   
                                float *tmp;
                                d *= -1.0F; // permutation ==> le déterminant change de signe
                                tmp = B->data[j];
                                B->data[j] = B->data[p];
                                B->data[p] = tmp;
                            }
                            /* À présent le pivot est à la colonne j, ligne j */
                            /* Traitement des lignes hors-pivot */
                            for (i = j+1; i < B->nr; i++)
                            {
                                int k ; // numéro de colonne
                                for (k = 0; k < B->nc; k++)
                                {
                                    float * test = mult_scalaire(B->data[j], (B->data[i][j] / B->data[j][j])); // À METTRE AVANT LA BOUCLE ?
                                    B->data[i][k] = B->data[i][k] - test[k];
                                }
                            }
                        }
                    
                        /* Calcul du dérminant */
                        for (l = 0; l < B->nr; l++)
                            d = d * B->data[l][l];  // déterminant = produit des éléments diagonaux
                    
                        /* Retour */
                        return d;
                    

                    Questions :

                    ─ Ligne 24 : je pense que tu dois mettre une valeur absolue. Il faut choisir le pivot parmi les plus grands coefficients possibles, mais grand en valeur absolue. Si tout les coefficients sont négatifs sauf un qui est nul, badaboum ! Mais je pense pas que l'erreur vienne de là car ça ne poserait problème que dans des cas particuliers.

                    ─ Lignes 42 et 43 (comme par hasard ce sont celles que tu as citées). Il y a un truc louche, je trouve. J'ai peut-être trouvé le pot aux roses mais je n'en suis pas sûr. Si c'était moi, j'aurais procédé ainsi :

                    (1) coeffmult := B(i,j) / B(j,j) à calculer avant la boucle for(k=0, k<nc)

                    Et, pour chaque k de la boucle for(k=0, l<nc) :

                    (2) B(i,k) := B(i,k) - coeffmult * B(j,k)

                    Ce que tu fais, si j'ai bien compris, c'est de calculer les coefficients coeffmult*B(j,k) (comme ça ressemble à mon calcul (1), je vals l'appeler le calcul (1'))pour toute la ligne, et de les ranger dans un tableau sur lequel pointe la variable 'test'. Mais ce calcul initial, tu dois le faire avant la boucle for(k=0, k<nc) ! Là, c'est redondant, et même pire. En effet, le calcul du coeff doit utiliser l'ancienne valeur de B(i,j). Lorsque tu modifies un par un les coefficients de la ligne i, tu finis par atteindre celui de n° j, et le calcul (2) le met à zéro. Du coup, lorsque tu traites les coefficients suivants, le calcul (1') est faussé : désormais B(i,j) vaut 0 et le coefficient vaut 0. (Tu peux vérifier ça en faisant afficher par printf la valeur de 'test[k]' avant le calcul de la ligne 43 lorsque k>j).

                    (Finalement j'aurais pu ne mettre dans la réponse que le dernier paragraphe, et peut-être même juste te dire de déplacer la ligne 42 avant la boucle (si mon hypothèse est juste), mais j'ai passé du temps sur ton listing, donc je te laisse passer du temps sur ma réponse... :soleil:)

                    (Et breizhbugs a raison pour les fuites mémoires. 'B' et 'test' sont des variables temporaires définies par des fonctions qui, j'imagine, utilisent une allocation dynamique de mémoire, qui n'est pas libérée.)

                    -
                    Edité par robun 7 octobre 2016 à 3:55:56

                    • Partager sur Facebook
                    • Partager sur Twitter
                      7 octobre 2016 à 12:44:51

                      TLHD a écrit:

                      Bonsoir, 

                      Complet je ne pourrais malheureusement pas, mais quelles fonctions veux-tu que je poste ? 


                      Définition de la structure, copie_matrice et multscalaire  (Comment fait mult_scalaire pour connaitre la dimension des tableau si tu ne leur passe pas la structure entière?)

                      (B->data[i][j] / B->data[j][j])

                      Ne renverra un nombre flottant//double que si data[i][j] est de type flottant double... Il faut cast au moins l'un des deux sinon...)

                      -
                      Edité par breizhbugs 7 octobre 2016 à 12:48:05

                      • Partager sur Facebook
                      • Partager sur Twitter
                      ** La doc, c'est comme le PQ: ça sert à se démerder tout seul **
                        9 octobre 2016 à 17:53:08

                        Déjà, je vous remercie vous deux pour votre implication ! 

                        @rubun, j'ai pris du temps pour effectuer toutes les modifications nécessaires et j'ai réglé les fuites mémoires ! 

                        Néanmoins, je tombe plus sur la valeur 0 mais sur "-nan(ind)" ce qui est plutôt bizarre...

                        loat determinant(struct matrix *A)
                        {
                            int i;              // Numéro de ligne, entre 0 et A->nr-1
                            int j;              // Numéro de colonne, entre 0 et A->nc-1
                            int l;              // Indice des éléments diagonaux, utile pour le produit des coefficients diagonaux (ligne 86)
                            float d = 1.0F;     // Variable contenant la valeur du déterminant
                            struct matrix *B;   // Copie de A dans B pour garder intact la matrice A
                            B = copie_matrice(A);
                            float * test = malloc (B->nc * sizeof(float)); //Tableau servant à effectuant une opération intermédiaire (Ligne 85)
                        
                            /* Déroulement du pivot */
                            // Méthode utilisée : 
                            // Pour chaque colonne j, on choisit un pivot à la ligne p.
                            // Si cette ligne n'est pas la ligne j (donc si le pivot n'est pas sur
                            // la diagonale), on permute les lignes j et p. Ainsi, à la fin du
                            // traitement de la colonne j, les pivots ont été ramenés aux j premières
                            // lignes.
                            for (j = 0; j < B->nc-1; j++)   // On choisira un pivot à chaque colonne (sauf la dernière)
                            {
                                /* Recherche du pivot de la colonne j */
                                // On le recherche dans les lignes situées à partir de j, car les
                                // pivots précédents ont été ramenées aux lignes 0 à j-1.
                                
                                int p = j;  			// Numéro de ligne du pivot
                                
                                for (i = j+1; i < B->nr; i++)
                                {   
                                	// On regarde si un meilleur pivot existe dans les lignes suivantes
                                    if (abs(B->data[i][j] - B->data[p][j] > 0))
                                        p = i;    
                                }
                        
                                if (p != j) 			// On permute les lignes j et p
                                {  
                                    float *tmp;
                                    d *= -1.0F; 		// On a permuté, par conséquent le déterminant change de signe. 
                                    tmp = B->data[j];
                                    B->data[j] = B->data[p];
                                    B->data[p] = tmp;
                                }
                        
                                /* À présent le pivot est à la colonne j, ligne j */
                                /* Traitement des lignes hors-pivot */
                                for (i = j+1; i < B->nr; i++)
                                {
                                    int k ; 			// Numéro de colonne
                                    float coeff; 
                                   
                                    coeff = (float)B->data[i][j] / B->data[j][j];
                                    test = mult_scalaire(B->data[j], coeff, B->nc);
                                    for (k = 0; k < B->nc; k++)
                                    {
                                        B->data[i][k] = B->data[i][k] - test[k];
                                    }
                                }
                            }
                         
                            /* Calcul du dérminant */
                            for (l = 0; l < B->nr; l++)
                                d = d * B->data[l][l];  // Déterminant d'une matrice triangulaire supérieure : produit des coefficients diagonaux.
                         
                            free(test);
                            free_matrix(B); 
                            return d;
                        }

                        Fonction copie_matrice et mult_scalaire : 

                        float *mult_scalaire(float *m, float c, int taille) 
                        {
                            int i; 
                            for (i = 0; i < taille; i++)
                            {
                                m[i] = c * m[i];
                            }
                            return m; 
                        }
                        struct matrix *copie_matrice(const struct matrix *m) {
                            struct matrix *cpy = new_matrix(m->nr, m->nc);
                            for (int i = 0; i < m->nr; i++) {
                                for (int j = 0; j < m->nc; j++) {
                                    cpy->data[i][j] = m->data[i][j];
                                }
                            }
                            return cpy;
                        }

                        Voilà ! 

                        Quand on obtient ce genre d'erreur en langage C, il faut regarder où généralement ? 



                        • Partager sur Facebook
                        • Partager sur Twitter
                          9 octobre 2016 à 18:18:13

                          nan, ça peut provenir d'une division 0/0.

                          Les éléments de la matrice sont des entiers ? (Je pose la question à cause du "(float)" de la ligne 49. D'ailleurs je ne suis pas sûr qu'il fasse ce que tu espères : agit-il seulement sur le numérateur, ou sur le résultat de la division ?) J'espère que ce n'est pas le cas !

                          Continue à regarder ce qui se passe aux environs de la ligne 50 en mettant des printf et en comparant avec un cas que tu auras résolu à la main.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            10 octobre 2016 à 11:07:17

                            Bonjour,

                            Les Nan c'est plutôt les opérations indéterminées 0/0 ∞-∞ 0⁰ etc.

                            TLHD a écrit:

                            [...]
                            Quand on obtient ce genre d'erreur en langage C, il faut regarder où généralement ?

                            La bonne question n'est pas «où» mais «avec quoi». Pour débusquer un bug dans un programme le debuger est le bon outil. Tu pourras  mettre des points d'arrêts, scruter les valeurs des variables, …
                            • Partager sur Facebook
                            • Partager sur Twitter
                            First solve the problem. Then, write the code. ~ John Johnson
                              10 octobre 2016 à 23:26:37

                              Les éléments de la matrice sont des flottants. 

                              J'ai enlevé le cast en float mais ça n'arrange rien. J'ai testé, c'est à ce niveau que cela ne va pas : 

                              coeff = B->data[i][j] / B->data[j][j];

                              Il y a une division 0/0 apparemment ! 

                              En mettant un point d'arrêt avant la ligne 44 il n'y a aucune valeur nulle sur ces variables, je suis toujours en train d'essayer de régler cela. 
                               

                              EDIT : J'ai testé sur une autre matrice, je tombe sur un résultat non nul mais qui est faux. 

                              -
                              Edité par TLHD 10 octobre 2016 à 23:38:53

                              • Partager sur Facebook
                              • Partager sur Twitter
                                11 octobre 2016 à 1:05:42

                                Mets le point d'arrêt juste avant cette ligne !

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  11 octobre 2016 à 13:03:03

                                  J'ai beaucoup appris en faisant cette exercice, ça aide de forcer sans rien lâcher ! 

                                  Le problème vient donc de la valeur de B->data[0][0].

                                  J'ai remis des points d'arrêts et des printf pour déterminer la partie du code qui pose un problème et c'est : 

                                   if (p != j)             // On permute les lignes j et p
                                          { 
                                              float *tmp;
                                              d *= -1.0F;         // On a permuté, par conséquent le déterminant change de signe.
                                              tmp = B->data[j];
                                              B->data[j] = B->data[p];
                                              B->data[p] = tmp;
                                          }



                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    11 octobre 2016 à 13:34:51

                                    Tu n'arrives pas à désigner précisément la ligne fautive ? Tu devrais faire afficher les lignes qui permutent avant et après. Si ça cloche, il faut regarder ligne par ligne ce qu'il se passe !

                                    Tiens, je n'avais pas remarqué ça (ligne 29) :

                                    if (abs(B->data[i][j] - B->data[p][j] > 0))

                                    Attention, |x| > |y| n'est pas équivalent à |x-y| > 0. Tu aurais dû faire (je crois) :

                                    if (fabs(B->data[i][j]) > fabs(B->data[p][j]))

                                    En fait, |x-y| > 0 est toujours vrai (par définition de la valeur absolue) !

                                    De plus tu as mal parenthésé ! En fait tu n'as pas écrit « si |x-y|>0 » mais « si |x-y>0| », ce qui veut dire tout autre chose : ça peut valoir abs(0) si x-y est <=0 et abs(1) si x-y>0, donc c'est vrai si x-y >0.

                                    Dernière chose : la fonction abs retourne la valeur absolue d'un entier. Ici ça ne change rien vu que tu calcule la valeur absolue de 0 ou 1 (de |x-y>0|).

                                    Bref, le pivot est donc choisi un peu n'importe comment... Tu ne t'en es pas rendu compte ? Tu n'as pas fait afficher les valeurs du pivot ? Tu n'as pas comparé avec un calcul à la main ? Ou bien c'est moi qui me plante ?

                                    Si un colonne contient des valeurs toutes <=0 dont une égale à 0.0, la condition x-y > 0 te fera choisir comme pivot 0.0.

                                    Mais bon, ça reste un cas très particulier, donc l'erreur est sûrement ailleurs...

                                    -
                                    Edité par robun 11 octobre 2016 à 14:20:21

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      14 octobre 2016 à 11:11:54

                                      C'était corrigé dans mon programme ! 

                                      Mais je n'y arrive franchement pas c'est frustrant surtout qu'en Python j'ai réussi à le faire en 3 jours.. 

                                      En testant avec d'autres matrices je tombe sur des résultats faux, c'est très bizarre. 

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        14 octobre 2016 à 17:58:36

                                        Comme le sujet m'intéresse (je prévois de faire la même chose avec des nombres qui seront des structures fraction), je peux t'aider si tu veux bien poster la définition du type et la définition des fonctions utiles qui n'ont pas encore été postées (en fait, tout ce qui me permettra de compiler et exécuter le programme chez moi ─ et reposte la version corrigée éventuellement). Dans ce cas, je trouverai le temps de regarder ça de plus près.

                                        (Ma stratégie sera de comparer chaque étape du calcul ─ je mettrai des printf partout ─ avec un calcul que j'aurais fait à la main en suivant le même algorithme. Elle est longue mais 100 % efficace. Du coup elle est moins longue que ne rien trouver.)

                                        -
                                        Edité par robun 14 octobre 2016 à 18:08:53

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          14 octobre 2016 à 18:07:01

                                          Je relisais un peu la discussion et juste en passant → fabs prend comme un argument un double. Ce n'est pas si grave que ça de lui filer un float à cause des promotions.

                                          Néanmoins il ne faut pas oublier que le standard propose quasiment toues les fonctions réelles en triple, une version pour les doubles, une version pour les float suffixée avec f et une version pour les long doubles suffixée avec l. Donc en gros fabs c'est pour les doubles, fabsf pout les floats et fabcsl pour les long doubles.

                                          Mais depuis C11 on dispose de macros génériques, au lieu d'inclure math.h il faut inclure tgmath.h (pout Type Generic MATH). Plus la peine de se casser la tête car la macro fabs appellera la bonne fonction en fonction du type de l'argument.

                                          Une dernière remarque → les floats n'ont que 6/7 chiffres décimaux significatifs, les doubles 14/15 et les long doubles 32/33. Par défaut si on ne précise rien une constante flottante sera interprétée comme un double.

                                          Un conseil, sauf besoin pressant contraire il vaut mieux utiliser des doubles que des floats en C.

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          First solve the problem. Then, write the code. ~ John Johnson
                                            16 octobre 2016 à 17:26:32

                                            Je t'ai envoyé un message privée Robun. 

                                            Je savais pas ça PicoDev, merci pour ton intervention ! 

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              16 octobre 2016 à 21:20:49

                                              TLHD : c'est bon, j'ai trouvé l'erreur (j'ai commencé à inspecter ça vers 20h45, donc ça ma pris 30 minutes). Méthode : copier le main.c et le "saloper" en mettant des printf partout (d'où l'intérêt de le copier...)

                                              (Remarque préliminaire : j'ai changé les coefficients du déterminant, je l'ai fait tourner avec un déterminant que j'avais calculé à la main il y a deux ou trois jours en prévision. Le résultat doit faire 6.0 et il trouve -10.0.)

                                              C'est ici :

                                                      for (i = j+1; i < B->nr; i++)
                                                      {
                                                          int k ;             // Numéro de colonne
                                                          float coeff;
                                                          
                                                          coeff = (float)B->data[i][j] / B->data[j][j];
                                                          test = mult_scalaire(B->data[j], coeff, B->nc);
                                                          for (k = 0; k < B->nc; k++)
                                                          {
                                                              B->data[i][k] = B->data[i][k] - test[k];
                                                          }
                                                      }
                                              

                                              Avec les printf ça ressemble à ça (c'est pour te donner une idée) :

                                                      for (i = j+1; i < B->nr; i++)
                                                      {
                                                          int k ; 			// Numéro de colonne
                                                          float coeff; 
                                              
                                                          printf("%d / Ligne du pivot : [%f %f %f]\n", i+1, B->data[j][0], B->data[j][1], B->data[j][2]);
                                                          coeff = B->data[i][j] / B->data[j][j];
                                                          printf("    Ligne %d : coeff = %f / %f = %f\n", i+1, B->data[i][j], B->data[j][j], coeff);
                                                          test = mult_scalaire(B->data[j], coeff, B->nc);
                                                          printf("    Ligne du pivot : [%f %f %f]\n", B->data[j][0], B->data[j][1], B->data[j][2]);
                                                          for (k = 0; k < B->nc; k++)
                                                          {
                                                              B->data[i][k] = B->data[i][k] - test[k];
                                                          }
                                              

                                              Je me suis aperçu que la ligne du pivot était elle aussi multipliée par le coefficient ! Dès le traitement de la ligne 2 on a :

                                              2 / Ligne du pivot : [3.000000 2.000000 -1.000000]
                                                  Ligne 2 : coeff = 2.000000 / 3.000000 = 0.666667
                                                  Ligne du pivot : [2.000000 1.333333 -0.666667]
                                              

                                              (On voit bien que la ligne du pivot a été multipliée par 0.666667.)

                                              Pareil à la ligne suivante :

                                              3 / Ligne du pivot : [2.000000 1.333333 -0.666667]
                                                  Ligne 3 : coeff = -1.000000 / 2.000000 = -0.500000
                                                  Ligne du pivot : [-1.000000 -0.666667 0.333333]
                                              

                                              Donc la fonction 'mult_scalaire' a modifié la ligne du pivot. Voyons de plus près cette fonction :

                                              float *mult_scalaire(float *m, float c, int taille) 
                                              {
                                                  int i; 
                                                  for (i = 0; i < taille; i++)
                                                  {
                                                      m[i] = c * m[i];
                                                  }
                                                  return m; 
                                              }
                                              

                                              Bingo ! Tu modifies les valeurs de m (la ligne du pivot) ! Il y a deux solutions :

                                              1) Créer un tableau local 'mcopie' et faire « mcopie[i] = etc. », puis retourner 'mcopie'... sauf que non ! Ça ne marchera pas car le tableau sera détruit quand on sortira de la fonction.

                                              2) Créer un pointeur mcopie, lui allouer une zone de mémoire nécessaire, faire « mcopie[i] = etc. » et retourner ce pointeur. Cette fois, le tableau n'est pas détruit car il n'a pas été créé par la fonction.

                                              Est-ce que tu vois ce qu'il reste à faire ?

                                              Je pense que tu dois retenir la méthode du "salopage par les printf" (à utiliser conjointement avec un calcul réalisé à la main), elle est efficace pour les petits programmes si on n'utilise pas de débogueur.

                                              ------

                                              Finalement je l'ai fait, parce que je brûlais d'envie de savoir si c'était la seule erreur. Donc j'ai fait :

                                              float *mult_scalaire(float *m, float c, int taille) 
                                              {
                                                  int i; 
                                                  float* mcopie = malloc(taille * sizeof(float));
                                                  for (i = 0; i < taille; i++)
                                                  {
                                                      mcopie[i] = c * m[i];
                                                  }
                                                  return mcopie; 
                                              }
                                              
                                              et à présent le programme marche ! (Les étapes intermédiaires affichées par les printf sont pile-poil celles de mon calcul à la main.)

                                              -----

                                              PS : j'ai dû corriger quelques détails, notamment un point-virgule oublié dans le fichier .h, un autre point-virgule je ne sais plus où (voir messages d'erreur), le cast inutile avant le calcul des coeffs (on en avait parlé plus haut) et, surtout, la ligne où on choisit le pivot le plus grand : tu avais laissé le test erronné de l'autre jour ! Pense à le corriger, ce n'est pas :

                                              if (abs(B->data[i][j] - B->data[p][j] > 0))
                                              

                                              (qui est toujours vrai) mais :

                                              if (fabs(B->data[i][j]) > fabs(B->data[p][j]))
                                              

                                              -
                                              Edité par robun 16 octobre 2016 à 21:56:45

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                17 octobre 2016 à 9:51:35

                                                J'y crois pas ça fonctionne enfin, en plus je me doutais absolument pas que ça pouvait venir de cette fonction.

                                                Concernant les quelques erreurs, c'est de ma faute, je ne t'ai pas envoyé la version que j'avais corrigé !

                                                En tout cas merci beaucoup pour ton implication, j'ai remarqué que j'avais besoin encore d'entraînement et de refaire un tour dans un livre pour bien saisir toutes les subtilités du C. 

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  17 octobre 2016 à 13:13:08

                                                  En tout cas, bien penser à libérer la matrice résultante de mult_scalaire avant un nouvel appel à cette fonction...
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  ** La doc, c'est comme le PQ: ça sert à se démerder tout seul **
                                                    17 octobre 2016 à 19:29:28

                                                    Ah oui, j'ai oublié de le faire ! (Je voulais surtout savoir si c'était la seule erreur donc je me suis un peu précipité...)

                                                    TLHD : il me semble qu'on soupçonnait tous depuis le début que cette fonction était en cause (très tôt, breizhbugs t'a demandé de la poster). Donc c'est un réflexe que tu dois avoir : soupçonner les fonctions. Mais surtout, ce qui t'a manqué, c'est de pister le bug comme je l'ai fait. À mon avis c'est ça qui t'a bloqué, pas ton niveau de connaissance du langage C.

                                                    breizhbugs:  heu... c'est quoi la technique pour libérer la matrice temporaire ? Il ne faut pas la libérer avant le 'return' puisqu'on va s'en servir après. Du coup je crois que cette matrice (en fait c'est une ligne) doit être déclarée et allouée dans la fonction appelante, et être un paramètre de mult_scalaire. C'est bien ça ? Si oui, il faut modifier cette fonction pour qu'elle ressemble à ça :

                                                    void mult_scalaire(float *m, float c, float *mcopie, int taille) ;
                                                    /* Arguments :
                                                       m : ligne de la matrice
                                                       c : coefficient multiplicatif
                                                       mcopie : ligne obtenue par la multiplication c*m
                                                       taille : nombre d'éléments des tableaux m et mcopie
                                                    */
                                                    



                                                    -
                                                    Edité par robun 17 octobre 2016 à 19:33:26

                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      17 octobre 2016 à 20:18:38

                                                      C'est l'appelant qui libère effectivement... Donc bien structurer le programme pour libérer la matrice temporaire!

                                                      Il n'est pas nécessaire de passer la matrice a mult_scalaire, l'ancienne déclaration peut convenir

                                                      float *mult_scalaire(float *m, float c, int taille) 

                                                      mais bien préciser dans la doc de la fonction que c'est l'appelant qui libère...

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      ** La doc, c'est comme le PQ: ça sert à se démerder tout seul **

                                                      Opération matricielle

                                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                      • Editeur
                                                      • Markdown