Forum Programmation.c++ Marquer un double comme étant non élaboré.

Posté par  .
Étiquettes : aucune
0
23
juin
2005
Je gère des grandeurs 'double'. Certaines sont déjà calculées, d'autres pas encore. Je cherche une solution élégante pour pouvoir les distinguées.

J'ai pensée à :
- associer un bool 'estElaboree' à chaque grandeur. Fonctionnellement c'est parfait, mais un peu lourd à gérer. Je double mon nombre de variables. Et puis il faut gérer la cohérence entre les grandeurs et les booléen à chaque ajout ou suppression de grandeurs.

-initialiser toutes mes grandeurs à une valeur spécifique constante (connue dès la compilation DOUBLE_NON_ELABOREE. Mais quelle valeur choisir ? :
. J'ai pensé à
const Double DOUBLE_NON_DEFINI = 1.0e31;
Ca marche, mais pas très élégant. Et si un jour un calcul donne pile poile 1.0e31 ?
. J'ai essayé
const Double DOUBLE_NON_DEFINI = numeric_limits::max();
Mais ça ne compile pas. Je pense que numeric_limits::max() n'est pas connu à la compilation, mais à l'exécution.

La solution doit fonctionner sous gcc, mais aussi être portable.
Vous avez des idées ?
(Nan?, inf?, définir la valeur comme n'étant pas constante peut-être ?).
Merci
  • # Nan, peut-être

    Posté par  (site web personnel) . Évalué à 3.

    Le problème est la portabilité. Il y a un exemple que tu peux utiliser dans libgoffice :
    http://cvs.gnome.org/viewcvs/goffice/goffice/utils/go-math.c(...)

    Autrement, il est bien sûr possible d'utiliser un bool, mais c'est plus élégant si c'est encapsulé dans une classe et encore mieux (question de goût ?) avec un template.
  • # Fais une classe

    Posté par  . Évalué à 3.

    Tu n'as qu'à faire un peu comme en Java avec la nuance type double et classe Double :

    Ce que tu cherches à représenter n'est pas un double, mais un objet à deux propriétés : une valeur et un caractère élaboré ou pas. Fais donc une classe doubleElaborable ou ce que tu veux qui contient un booléen et un double.

    C'est très simple, et c'est propre (à mon avis).

    PS : pour pouvoir les distinguer (mordre) ;)
    • [^] # utilise Nan du standart IEEE

      Posté par  . Évalué à 4.

      #include <math.h>

      main() {

      double d=NAN;

      if(isnan(d)) {
      printf("d est non défini\n");
      }

      d=-1;

      d=sqrt(d);

      if (isnan(d)) {
      printf("d est non défini\n");
      }
      }

      tu compiles avec gcc -D_ISOC99_SOURCE /tmp/essai.c -o /tmp/essai -lm

  • # Double et C++

    Posté par  . Évalué à 3.

    Lis la norme IEE-754-1985 qui définit les nombres à virgule flottante. Il précise que les valeurs INF et Nan sont définies, et gcc/g++ sait les gérer. C'est Nan que j'utiliserais (puisque c'est vrai).

    En C++, tu peux définir une classe dérivant immédiatement de double pour éviter les transtypages et autres.

    class ElaboratedDouble : public double
    {
    public:
    bool defined;
    }

    Tu peux également redéfinir l'opérateur de casting (double) (même si redéfinir les opérateurs de casting pose toujours plus de problème que cela n'en résoud) et tenter de lancer une exception si la valeur n'est pas définie.
    • [^] # Re: Double et C++

      Posté par  . Évalué à 1.

      Je pencherais meme vers une solution avec une classe gerant un ensemble de doubles, l'avantage est qu'au lieu d'avoir un booleen pour chaque double, il suffit de gerer un bitfield de longueur suffisante ce qui est beaucoup plus economique en memoire

      ex :

      class ElaboratedDoubleManager
      {
      char* double_defined_bitfield;
      double* double_list;

      ElaboratedDoubleManager(int size)
      {
      int taille_bitfield;
      double_list=new double[size];

      if (size % (sizeof char) == 0)
      taille_bitfield = size / (sizeof (char));
      else
      taille_bitfield = size / (sizeof (char)) + 1;

      double_defined_bitfield=new char[taille_bitfield];
      }



      ...

      }
  • # Merci à tous

    Posté par  . Évalué à 1.

    Visiblement, vous en avez sous la pédale.
    Des idées originales , des exemples compilables.

    Je serais bien parti sur le NaN, car il implique de ne modifier que 2 lignes dans mon code. Mais il semble que ça ne soit pas compatible avec l'option -ansi que l'on m'impose. Et j'ai un peu peur de la portabilite.

    Je pourrais faire une classe ou un template. Mais ça implique pas mal de changements.

    Une variante :
    typedef double* elaboredDouble;
    ou
    typedef boost::shared_ptr<double> elaboredDouble;
    Cela me ramenne à la solution java.
    C'est portable sans risque (au moins la première forme).
    C'est transposable à tous les types de base.
    Mais ça me demande pas mal de changement.

    A suivre.
    Encore merci.
    • [^] # Re: Merci à tous

      Posté par  . Évalué à 2.

      Tu peux très bien utiliser NaN et rester ANSI,

      la norme ANSI est au niveau de ton code source,
      la norme qu'on exploite est la norme des flottants IEEE

      Autrement dit, tu recopie le code source de isnan et tu défini toi-même la constante NAN.

      Ou alors si ça t'amuse tu les recode.

      Je me suis amusé à ça l'autre jour. En gros pour qu'un double soit NaN il suffit de mettre 0x7ff dans les 12 premiers bits et n'importe quoi de non nul dans les autres. (cf norme)

      Pareil pour faire isnan, il faut mettre deux trois Xor bien placés.

      conclusion

      La norme IEEE est implémentée au niveau des processeurs, ANSI c'est juste de la portabilité au niveau code source, rien ne t'empêche donc de recopier ou de reécrire la constante et la routine. :-)
      • [^] # Nan...

        Posté par  . Évalué à 1.

        Et comment affecte-t-on les bits d'un double ?

        avec un "union" ?

        L'exemple de 'nan.h' n'est pas encouragant.


        # define NAN (__builtin_nanf(""))

        #elif defined__GNUC__

        # define NAN \
        (__extension__ \
        ((union { unsigned __l __attribute__((__mode__(__SI__))); float __d; }) \
        { __l: 0x7fc00000UL }).__d)

        #else

        # include <endian.h>

        # if __BYTE_ORDER == __BIG_ENDIAN
        # define __nan_bytes { 0x7f, 0xc0, 0, 0 }
        # endif
        # if __BYTE_ORDER == __LITTLE_ENDIAN
        # define __nan_bytes { 0, 0, 0xc0, 0x7f }
        # endif

        static union { unsigned char __c[4]; float __d; } __nan_union
        __attribute_used__ = { __nan_bytes };
        # define NAN (__nan_union.__d)

        #endif
        • [^] # Re: Nan...

          Posté par  . Évalué à 1.

          Pour modifier les bits d'un double, voici une methode petit cochon.


          main()
          {
          double a=1;
          unsigned long long *b;

          b=(unsigned long long *)&a;

          *b=0x7ff0000000000001;

          if (isnan(a)) {
          printf("la valeur de a est %lf \n",a);
          }


          }


Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.