Partage
  • Partager sur Facebook
  • Partager sur Twitter

long double et g++

    28 mai 2014 à 22:57:23

    Salut,

    Je viens de découvrir que ma version de MinGW semble corrompue. Il semble que la gestion des "long double" ne marche pas comme prévu (ça marche parfaitement sur VC++2013 et avec une ancienne version de Mingw). Je veux bien essayer avec clang mais ça n'avance à rien vu que sur Windows ça se base pas encore sur libc++ mais sur libstdc++, donc même problème. Sur http://coliru.stacked-crooked.com/ j'ai réussi à faire tourner le programme avec succès.

    De plus llround() compile et marche parfaitement quand l'argument est une constante mais ne passe pas l'étape du link quand l'argument est une variable (même avec une variable mise à const). mais marche parfaitement avec les autres compilateurs.

    Voici le code en question:

    #include <cmath>
    #include <iostream>
    #include <limits>
    
    int main()
    {
      std::cout.precision(std::numeric_limits<float>::digits10);
      double PIf = acos(-1.0F);
      std::cout << "PIf " << sizeof(float) << " :  " << PIf << std::endl;
    
      std::cout.precision(std::numeric_limits<double>::digits10);
      double PId = acos(-1.0);
      std::cout << "PId " << sizeof(double) << " :  " << PId << std::endl;
    
      std::cout.precision(std::numeric_limits<long double>::digits10);
      long double PIl = std::acos(-1.0L);
      std::cout << "PIl " << sizeof(long double)  << " : " << PIl << std::endl;
    }

    le résultat retourné est 

    PIf 4 :  3.14159
    PId 8 :  3.14159265358979
    PIl 12 : -8.8796093704934495e+043

    Je ne sais pas si c'est mon installation ou c'est le cas de la dernière version de mingw.

    • Partager sur Facebook
    • Partager sur Twitter
      29 mai 2014 à 22:25:17

      Essaye une version du projet MinGW-W64: https://sourceforge.net/projects/mingwbuilds/files/host-windows/releases/ 

      L'affichage semble correct, contrairement à la version venant de MinGW.

      Apparemment mingw utilise le printf de msvcrt qui ne connaît pas le type long double de gcc (80 bits), donc il affiche comme un double (64 bits). Ça donne la même valeur, -8.8796093704934495e+043, si tu fais:

      double *pPIl = reinterpret_cast<double*>(&PIl);
      std::cout << *pPIl << std::endl;
      



      • Partager sur Facebook
      • Partager sur Twitter
        30 mai 2014 à 0:35:00

        D'accord je vois, mais ça n'explique pas le fait que llround() ne soit pas linké. De toute façon, j'utilise depuis cet après midi la version de mingw livrée avec Qt5.3 et elle a l'air de très bien marcher.
        • Partager sur Facebook
        • Partager sur Twitter
          30 mai 2014 à 2:47:56

          J'avais mis le sujet à résolu pensant que mes problème étaient réglés avec cette version.

          La version livrée avec Qt contient des bugs. Maintenant c'est les "double" qui semblent être mal gérés (ça marche parfaitement sur VS2013, sur la MinGW qui est "allergique" aux long double et sur clang qui est dispo enligne à l'adresse http://coliru.stacked-crooked.com/).

          Le bout de code qui montre ce problème est cette fois-ci:

          #include <iostream> // même comportement avec printf
          #include <cmath> // même comportement avec les fonctions C (sqrt et pow)
          
          struct Elem
          {
          	double x;
          	double y;
          };
          
          double distance(Elem e1, Elem e2)
          {
          	return std::sqrt(std::pow(e1.x+0.0-e2.x,2)+std::pow(e1.y+0.0-e2.y,2));
          }
          
          double distance_ptr(Elem* e1, Elem* e2)
          {
          	return std::sqrt(std::pow(e1->x+0.0-e2->x,2)+std::pow(e1->y+0.0-e2->y,2));
          }
          
          int main()
          {
          	Elem e1={0,0};
          	Elem e2={std::cos(2.0),std::sin(2.0)};
          	{// "OK" est printé
          		double d=distance(e1,e2);
          		if(d==1.0)
          			std::cout<<"1. OK"<<std::endl;
          		else
          			std::cout<<"1. KO"<<std::endl;
          	}
          	{
          		double d=distance_ptr(&e1,&e2);
          		if(d==1.0)
          			std::cout<<"2. OK"<<std::endl;
          		else
          			std::cout<<"2. KO"<<std::endl;
          	}
          	{
          		double d=distance_ptr(&e1,&e2);
          		std::cout<<"result: "<< d <<std::endl;
          		if(d==1.0)
          			std::cout<<"3. OK"<<std::endl;
          		else
          			std::cout<<"3. KO"<<std::endl;
          	}
          	return 0;
          }
          

          Le résultat prévu c'est que des "OK" et l'affichage du 1 (1.0000 avec la version C). Mais voici ce que ça me donne:

          1. OK
          2. KO
          result: 1
          3. OK

          Par contre, le programme se comporte normalement quand on remplace les "double" par "long double" std::pow std::sqrt std::cos et std::sin par powl sqrtl cosl et sinl et en rajoutant le suffix L après les constantes (sur tous les environnements cités jusqu'à présent, sauf pour l'affichage de result sur la version officielle de Mingw).

          Avez vous aussi eu affaire à ce genre de "petits bugs" d'implémentation? J'ai l’impression que le seul environnement qui semble fiable (mais incomplet: pas de user defined literals, par exemple) sur mon Windows c'est VS2013 et rien d'autre (à moins d'installer cygwin et regarder s'il gère bien ces "petits détails").

          -----------

          [EDIT]

          PS: On observe le même problème quand on utilise des références à la place des pointeurs.

          -
          Edité par d@rk-marouane 30 mai 2014 à 2:57:17

          • Partager sur Facebook
          • Partager sur Twitter
            30 mai 2014 à 4:17:35

            d@rk-marouane a écrit:

            D'accord je vois, mais ça n'explique pas le fait que llround() ne soit pas linké. 

            Apparemment, llround n'est pas présent dans toutes les versions de mingw provenant de mingw.org: https://sourceforge.net/p/mingw/bugs/2175/?limit=25 

            Mais le compilateur peut faire des optimisation à la compilation et remplacer llround de constante par le résultat.

            d@rk-marouane a écrit:

            La version livrée avec Qt contient des bugs. 

            Ce ne sont pas des bugs en tant que tels, c'est dû à l'option par défaut de gcc: -mfpmath=387 qui fait que la lecture d'un flottant au milieu d'un calcul peut modifier sa valeur.

            En passant "-msse2 -mfpmath=sse" à gcc, tu devrais le même résultat à chaque fois (mais pas forcément "OK", puisque les flottants et == ne vont pas toujours ensemble).

            -
            Edité par alexisdm 30 mai 2014 à 4:18:25

            • Partager sur Facebook
            • Partager sur Twitter
              30 mai 2014 à 11:33:35

              Je vois qu'en effet, selon les options d'optimisation, on obtient des résultats différents. Le problème en question vient de l' "excess precision".

              Il y a aussi d'autres méthodes pour régler ce problème:

              -> Printer la valeur du flottant

              -> utiliser des variables "volatile" ou mettre un *reinterpret_cast<volatile double*>(&d)

              -> Ou encore rajouter l'option de compilation "-ffloat-store" ou "-msse2 -mfpmath=sse" (comme l'a dit @alexisdm)

              -> Il y a d'autres solutions proposées ici: http://stackoverflow.com/questions/503436/how-to-deal-with-excess-precision-in-floating-point-computations

              Bon là ça nous donne d'autres détails à prendre en compte quand on programme avec des valeurs flottantes/double flottantes...etc. Moi qui croyait que la sémantique de ces types là était simple à comprendre.

              Est-ce qu'on peut créer un sujet tout en haut de la section C ou C++ pour énumérer ces détails qui peuvent faire perdre à des honnêtes gens un temps précieux?

              -------------

              [EDIT]

              alexisdm a écrit:

              (mais pas forcément "OK", puisque les flottants et == ne vont pas toujours ensemble)

              C'était mon but initial. Je voulais trouver un petit exemple où le == ne marchait pas là où il "devrait" et c'est là que j'ai remarqué le caractère presque imprévisible de la chose.

              -
              Edité par d@rk-marouane 30 mai 2014 à 11:38:54

              • Partager sur Facebook
              • Partager sur Twitter

              long double et g++

              × 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