IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Simplifier la fonction de conversion si possible


Sujet :

C

  1. #1
    Inactif  

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    534
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 534
    Par défaut Simplifier la fonction de conversion si possible
    Salut,

    Ma fonction de conversion d'une chaîne de caractères vers un "long double" se sert de pleins de "return". C'est le "code du goret" comme diraient certains.

    Voici la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    int string_to_ldouble( const char * z , long double * val , const char point  )
    {   
        int sign = 1 ;
        long double po = 1 ;
        long double v = 0.0 ;
        size_t i = 0 ;
     
        if( z == NULL ) return -1  ;   // la chaîne est null 
        while( z[i] == ' ')  i++ ;
        if( z[i] == '\0' )  return 1  ;  // la chaîne est vide
     
        if( z[i] == '-' )  sign = -1 ; 
        if( z[i] == '+'  ) sign = 1 ;
        if( z[i] == '+' || z[i] == '-' ) i++ ;
     
        while( z[i] == ' ' ) i++ ;
        if( z[i] == '\0' )     // il n'y a plus rien apès le signe
        { 
          return 2 ;
        }
     
        for(  ; z[i] &&  ( isdigit(z[i])  ) ; i++ )
        v  = v * 10  + ( z[i]  - '0' ) ;
     
        if( z[i] != point )
        { while ( z[i] )
          if ( z[i++] != ' ' ) return 3  ;  // est-ce un entier ?
        }
        else
        if( z[i] == point && isdigit(z[i+1] ) )
        {    
          i++ ;
          for( ; z[i]  && ( isdigit(z[i] ) ) ; i++ )
          {
             po *= 10 ;
             v =  v + ( z[i] - '0' ) / po  ;
          }
        }
     
        while ( z[i] )
        if ( z[i++] != ' ' ) return 4  ;  // la fin de la chaîne est-elle propre ?
     
        v = sign * v    ;
        *val = v ;
     
        return 0 ;  // zéro pas de problème 
    }
    Si vous pouvez trouver une meilleure implémentation qui se passe des "return", je suis prêt à l'étudier dans la mesure où elle respecte les conditions de validité de la conversion.

    Ma fonction est pleine de redondances, mais je ne vois pas comment les corriger sans perturber ses règles de validité.

  2. #2
    Membre confirmé
    Inscrit en
    Avril 2007
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 82
    Par défaut
    Salut ,

    et si tu utilises une variable 'ret' , dans ton premier if où tu fais return -1 par exemple , tu met ret à -1 et le reste du code entre else {} et ainsi de suite ?
    tout à la fin alors return ret. ( que tu initialises à 0 si pas de probleme ) .

    [edit] et ne pas oublier les forcages de boucle si ton return était dans une boucle

  3. #3
    Inactif  

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    534
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 534
    Par défaut
    Salut,

    Effectivement j'avais pensé à une variable "ret" initialisée à zéro, qui pouvait incrémenter avec le niveau d'erreur.

    Mais dans la pratique cela mènerait à alourdir le code (en écriture ) avec des conditions "if..else", pour pister la chronologie la conversion.

    Mais si vous avez une idée, n'hésitez-pas. La principale chose à respecter, c'est la morphologie de la chaîne à traiter, le traitement caractères vers "long double" reste assez trivial.

  4. #4
    Membre éprouvé
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Par défaut
    c'est un des rares cas d'usage du goto a mon sens

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    int mafunc()
    {
    int rc = 0;
    if(....)
    {
    rc = 1;
    goto err;
    }
     
    if(...)
    {
    rc = 12;
    goto err;
    }
     
    err:
    return rc;
    }

  5. #5
    Inactif  

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    534
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 534
    Par défaut
    Salut,

    Dark_Ebola,

    Effectivement je ne vois pas dans cette situation de ma fonction, comment échapper à des "return" ou à des "goto".

    Le "code du goret" c'est certes non souhaitable, quand on ne peut rien faire d'autres...

  6. #6
    Expert confirmé

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Par défaut
    Citation Envoyé par dj.motte
    Salut,

    Dark_Ebola,

    Effectivement je ne vois pas dans cette situation de ma fonction, comment échapper à des "return" ou à des "goto".

    Le "code du goret" c'est certes non souhaitable, quand on ne peut rien faire d'autres...
    Il y a toujours une solution, tu crées une variable res et avec des if/else, tu mets correctement cette variable à jour pour le dernier return.

    Mais dans ton cas, je fais exactement comme toi.

    Jc

  7. #7
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par dj.motte
    Si vous pouvez trouver une meilleure implémentation qui se passe des "return", je suis prêt à l'étudier dans la mesure où elle respecte les conditions de validité de la conversion.
    Avant de modifier le code, peux-tu montrer le test unitaire qui montre la validité de ton code ?

  8. #8
    Inactif  

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    534
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 534
    Par défaut
    Salut,

    Je ne sais pas trop ce que veut dire un "test unitaire", mais pour y voir mieux voici mon code simplifié :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
     
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
     
     
    int     cget_line(  char * s, const char * msg, const size_t nb ) ;
    int     string_to_ldouble( const char * z , long double * val , const char point  ) ;
     
     
     
    int cget_line(  char * s, const char * msg, const size_t nb )
    {  int c ;
      size_t w = 0  ;
      if( s == NULL  || ! nb  ) return  2 ;
     
      if( strlen(msg) > 0 )  printf("%s", msg ) ;
      fflush(stdout) ;
     
      while ((c = fgetc (stdin)) != '\n' && c != EOF)
      {
        if( w < nb - 1 )
        s[w++] = c;
        else
        {
          while((c = fgetc(stdin)) != '\n' && c != EOF);
          return 1 ;
        }
      }
      s[w] = '\0';
      return 0 ;
    }
     
    int string_to_ldouble( const char * z , long double * val , const char point  )
    {   
        int sign = 1 ;
        long double po = 1 ;
        long double v = 0.0 ;
        size_t i = 0 ;
     
        if( z == NULL ) return -1  ;   // la chaîne est null 
        while( z[i] == ' ')  i++ ;
        if( z[i] == '\0' )  return 1  ;  // la chaîne est vide
     
        if( z[i] == '-' )  sign = -1 ; 
        if( z[i] == '+'  ) sign = 1 ;
        if( z[i] == '+' || z[i] == '-' ) i++ ;
     
        while( z[i] == ' ' ) i++ ;
        if( z[i] == '\0' )     // il n'y a plus rien apès le signe
        { 
          return 2 ;
        }
     
        for(  ; z[i] &&  ( isdigit(z[i])  ) ; i++ )
        v  = v * 10  + ( z[i]  - '0' ) ;
     
        if( z[i] != point )
        { while ( z[i] )
          if ( z[i++] != ' ' ) return 3  ;  // est-ce un entier ?
        }
        else
        if( z[i] == point && isdigit(z[i+1] ) )
        {    
          i++ ;
          for( ; z[i]  && ( isdigit(z[i] ) ) ; i++ )
          {
             po *= 10 ;
             v =  v + ( z[i] - '0' ) / po  ;
          }
        }
     
        while ( z[i] )
        if ( z[i++] != ' ' ) return 4  ;  // la fin de la chaîne est-elle propre ?
     
        v = sign * v    ;
        *val = v ;
     
        return 0 ;  // zéro pas de problème 
    }
     
     
    void do1()
    { char z[80] ;
      int r = 1 ;
      int res = 0 ;  
      long double d = 0 ;
     
      while( d != -99 )
      { memset( z, 0 , sizeof(z) ) ;
        d= 0.0;
        r = cget_line( z, "saisir un double -99 pour quitter\n", sizeof(z)-1 ) ;
     
        if( r == 2 )
        { printf("erreur globale\n") ;
          continue ;
        }
        else
        if( r == 1 )
        { printf("saisie trop longue\n") ;
          continue ;
        }
        res = string_to_ldouble( z, &d, '.' ) ;
     
        if( res != 0 )
        { printf("erreur conversion res= %d\n", res ) ;
          continue ;
        }
        else 
        printf("Double= %Lf\n", d ) ;
     
      }
    }
     
    int main( int argc , char * argv [] )
    { 
      do1() ;
      return 0 ;
    }
     
    ///////////fin
    La question reste entière, comment se passer des "return", dans "string_to_ldouble", sans introduire de l'écriture redondante ?

    La question porte bien entendu sur "string_to_ldouble". Le "code du goret", comment s'en passer ?

  9. #9
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par dj.motte
    Je ne sais pas trop ce que veut dire un "test unitaire",
    Quel est la spécification de la fonction ?
    Comment le comportement de la fonction a-t-il été vérifié ?

  10. #10
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    entièrement d'accord avec toi Emmanuel...

    La fonction string_to_ldouble me semble horriblement compliquée pour ce que je comprend de ce qu'elle est censée faire...

    Mais pour être bien sûr, je confirme qu'il serait plus que souhaitable d'avoir la définition de ce que l'on veut faire...

  11. #11
    Inactif  

    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    534
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 534
    Par défaut
    Salut

    Cette fonction "string_to_ldouble" doit permettre la conversion d'une chaîne de caractères en "long double" en vérifiant la morphologie de la chaîne.

    Il existe déjà des fonctions qui permettent ce genre de conversion mais elles ne correspondent pas à mon attente. par ex ( strtold )

    Le but étant d'avoir la même souplesse de saisie que dans une cellule d'un tableur comme Excel.

    Par ex :
    " + 2121" => ok
    " - 22121.9" => ok
    " .987 " => ok

    " 2121. " => err
    " - 2121.2a" => err
    " . " => err
    " + " => err
    " - " => err

    Je pourrais certes résoudre le problème des espaces en vidant la chaîne de tous ses espaces avant de la soumettre à "strtold". Mais dans ce cas une saisie comme :

    " + 9 6 . 99 67 " aboutirait, alors que je considère que la forme est incorrecte.

    Voici une jolie fonction, mais elle ne correspond pas .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    long double atod(char *s)
    {
    	long double a = 0.0;
    	int e = 0;
    	int c;
    	while ((c = *s++) != '\0' && isdigit(c)) {
    		a = a*10.0 + (c - '0');
    	}
    	if (c == '.') {
    		while ((c = *s++) != '\0' && isdigit(c)) {
    			a = a*10.0 + (c - '0');
    			e = e-1;
    		}
    	}
    	if (c == 'e' || c == 'E') {
    		int sign = 1;
    		int i = 0;
    		c = *s++;
    		if (c == '+')
    			c = *s++;
    		else if (c == '-') {
    			c = *s++;
    			sign = -1;
    		}
    		while (isdigit(c)) {
    			i = i*10 + (c - '0');
    			c = *s++;
    		}
    		e += i*sign;
    	}
    	while (e > 0) {
    		a *= 10.0;
    		e--;
    	}
    	while (e < 0) {
    		a *= 0.1;
    		e++;
    	}
    	return a;
    }

Discussions similaires

  1. Fonction de conversion de nombre en lettres
    Par david_chardonnet dans le forum Langage
    Réponses: 21
    Dernier message: 08/12/2021, 17h51
  2. Fonction de conversion de volume
    Par soso78 dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 23/08/2005, 21h12
  3. [TestStand] Fonction de conversion...
    Par capblans dans le forum Autres langages
    Réponses: 4
    Dernier message: 26/04/2005, 08h58
  4. Réponses: 5
    Dernier message: 12/01/2005, 20h58
  5. Fonction de conversion de COLORREF en hexadécimal?
    Par charliejo dans le forum MFC
    Réponses: 4
    Dernier message: 21/02/2004, 18h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo