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 :

Quelques précisions sur le type double


Sujet :

C

  1. #1
    Membre confirmé
    Homme Profil pro
    amateur
    Inscrit en
    Octobre 2007
    Messages
    731
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Octobre 2007
    Messages : 731
    Points : 460
    Points
    460
    Par défaut Quelques précisions sur le type double
    Bonjour,

    Il y a certaines choses qui m'échappent. En effet, selon la MSDN, le type double peut contenir des chiffre allant de 1.7E-308 à 1.7E+308 or par exemple dans le code suivant que je mette la variable A de type int ou double, à partir du moment ou je dépasse 10 digits donc une valeur >= 1E11, le compilateur m'insulte en me disant : "[Warning] integer constant is too large for "long" type".


    De plus quand par exemple j'envoie 1E10 à la fonction NOMBRE_DE_DIGITS, il me renvoi la valeur 9 alors que je devrais avoir 10. Si je mets 1.000.000.001, il me renvoi bien 10. Problème de précision ou ma formule est fausse. J'ai testé de 1 à 10 toute les puissances de 10 et ça ne marche pas pour les valeurs comprise entre [1E10, 1.000.000.001[.

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
     
    int NOMBRE_DE_DIGITS( double VALEUR, int BASE );
     
    int main()
    {
        float A=1000000000;
     
        int B=NOMBRE_DE_DIGITS(A, 10);
     
        printf("%d \n", B);
     
        getchar();
    }
     
    int NOMBRE_DE_DIGITS( double VALEUR, int BASE )
    {
        if ( BASE <= 1 )
           {
                  printf("\nERREUR DANS LA FONCTION NOMBRE_DE_DIGITS\n   - LA BASE NE PEUT ETRE INFERIEURE OU EGALE A 1\n");
           }
     
        if ( VALEUR == 0 || VALEUR == 1)
           {
                  return 1;
           }
     
        if ( BASE > 1 )
           {
                  return (floor( log(abs(VALEUR))/log(BASE) ) +1);
           }
    }
    UNE REPONSE UTILE : &|| UN PROBLEME RESOLU :

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return (floor( log(fabs(VALEUR))/log(BASE) ) +1);
    abs(), c'est pour des entiers.
    Ceci étant, tu risques d'avoir quand même des problèmes dûs à l'imprécision du calcul (notamment celui du log) pour de grandes valeurs de VALEUR.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Membre confirmé
    Homme Profil pro
    amateur
    Inscrit en
    Octobre 2007
    Messages
    731
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Octobre 2007
    Messages : 731
    Points : 460
    Points
    460
    Par défaut
    Ok pour fabs, je ne savais pas.

    Pour la précision de log, pourquoi serait-ce moins précis que sur n'importe quelle calculette ?

    Et pour le fait que je ne puisse pas mettre de plus grand nombre dans un double que dans un int ? Avez vous une idée ?

    Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double C=log(fabs(A))/log(10);
    me retourne 8.999999999999998200000000000000 alors que cela devrait être 9

    Merci
    UNE REPONSE UTILE : &|| UN PROBLEME RESOLU :

  4. #4
    Membre éclairé
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Points : 842
    Points
    842
    Par défaut
    Les imprécisions dues aux nombres flottants
    Chez moi ta fonction retourne bien 9
    Plus tu pédales moins fort, moins t'avances plus vite.

  5. #5
    Membre confirmé
    Homme Profil pro
    amateur
    Inscrit en
    Octobre 2007
    Messages
    731
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Octobre 2007
    Messages : 731
    Points : 460
    Points
    460
    Par défaut
    Citation Envoyé par darkwall_37 Voir le message
    Ok pour fabs, je ne savais pas.

    Pour la précision de log, pourquoi serait-ce moins précis que sur n'importe quelle calculette ?

    Et pour le fait que je ne puisse pas mettre de plus grand nombre dans un double que dans un int ? Avez vous une idée ?

    Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double C=log(fabs(A))/log(10);
    me retourne 8.999999999999998200000000000000 alors que cela devrait être 9

    Merci
    Oui cette ligne de code doit retourner 9 mais pas la fonction qui doit retourner 10 ! Tu es bien sûr que chez toi cette ligne de code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double C=log(fabs(A))/log(10);
    te renvoi 9 ? dans ce cas là cela viendrait du PC ?!
    UNE REPONSE UTILE : &|| UN PROBLEME RESOLU :

  6. #6
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par darkwall_37 Voir le message
    à partir du moment ou je dépasse 10 digits donc une valeur >= 1E11, le compilateur m'insulte en me disant : "[Warning] integer constant is too large for "long" type".
    Normal, c'est effectivement une constante entière (sans virgule). Rajoute ".0" à la fin de ta constante et il ne devrait plus gueuler.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  7. #7
    Membre confirmé
    Homme Profil pro
    amateur
    Inscrit en
    Octobre 2007
    Messages
    731
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Octobre 2007
    Messages : 731
    Points : 460
    Points
    460
    Par défaut
    Apparement cela ne marche pas non plus, en tout cas chez moi. Voici le code que j'execute au cas où j'aurais manqué quelque chose.

    MAIN.C
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
     
    #include "./BIBLIOTHEQUE.h"
     
    int main()
    {
     
        double ENTIER = 20000000000.0; 
        double *TABLEAU  = NULL;
        int *TAILLE   = malloc(sizeof(int));
        ENTIER_DANS_TABLEAU(ENTIER, &TABLEAU, TAILLE);
     
        double VALEUR   = 2;
        double EXPOSANT = 10;
        double RESULTAT = PUISSANCE(VALEUR, EXPOSANT);
     
        int V_BASE = 11111111;
        int BASE   = 2;
        double DECIMAL=VERS_LA_BASE_DECIMALE(V_BASE, BASE);
     
        printf("\n\nEN DECIMAL = %.0f", DECIMAL);
     
        printf("\n\nPUISSANCE = %.0f", RESULTAT);
     
        printf("\n\nENTIER DANS TABLEAU : ");
     
        int i;
        for ( i=(*TAILLE-1) ; i>=0  ; i-- )
           {
                  printf("%.0f", TABLEAU[i]);
            }
     
        getchar();
    }

    HEADER
    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
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
     
    //PROTOTYPES////////////////////////////////////////////////////////////////////
    int NOMBRE_DE_DIGITS( double VALEUR, int BASE );
    double PUISSANCE( double VALEUR, double EXPOSANT );
    void ENTIER_DANS_TABLEAU( double VALEUR, double **TABLEAU, int *TAILLE_TABLEAU );
    double VERS_LA_BASE_DECIMALE( double VALEUR, int BASE );
    ////////////////////////////////////////////////////////////////////////////////
     
     
     
    //FONCTIONS/////////////////////////////////////////////////////////////////////
     
    ////////////////////////////////////////////////////////////////////////////////
    // NOMBRE_DE_DIGITS : Calcul le nombre de digits du nombre décimal dans la base considérée
    ////////////////////////////////////////////////////////////////////////////////
    // Entrée :
    //   VALEUR : double
    //   BASE   : int
    //
    // Pré-Conditions :
    //   BASE>1
    //
    // Sortie : 
    //   RESULTAT : int
    //
    // Post-Condition :
    //   ...
    ////////////////////////////////////////////////////////////////////////////////
     
    int NOMBRE_DE_DIGITS( double VALEUR, int BASE )
    {
        if ( BASE <= 1 )
           {
                  printf("\nERREUR DANS LA FONCTION NOMBRE_DE_DIGITS\n   - LA BASE NE PEUT ETRE INFERIEURE OU EGALE A 1\n");
           }
     
        if ( VALEUR == 0 || VALEUR == 1)
           {
                  return 1;
           }
     
        if ( BASE > 1 )
           {
                  return (floor( log(abs(VALEUR))/log(BASE) ) +1);
           }
    }
     
    ////////////////////////////////////////////////////////////////////////////////
    // PUISSANCE : Calcul la puissance d'un nombre
    ////////////////////////////////////////////////////////////////////////////////
    // Entrée :
    //   VALEUR : double
    //   EXPOSANT : double
    //
    // Pré-Conditions :
    //   VALEUR !=0
    //
    // Sortie : 
    //   RESULTAT : double
    //
    // Post-Condition :
    //   RESULTAT=VALEUR^EXPOSANT
    //////////////////////////////////////////////////////////////////////////////// 
     
    double PUISSANCE( double VALEUR, double EXPOSANT )
    {    
          double RESULTAT=1;  
          int I=0;    
     
          if ( EXPOSANT != floor(EXPOSANT) || VALEUR == 0 )
             {
                      printf("\nERREUR DANS LA FONCTION PUISSANCE\n   - VERIFIER QUE VOTRE EXPOSANT N'EST PAS UN REEL\n   - VERIFIER QUE VOUS NE CALCULEZ PAS LA PUISSANCE DE 0\n");
             } 
     
        else {
                  if ( EXPOSANT==0 || VALEUR==1 )
                     {
                              return RESULTAT;
                     }
     
                  if ( EXPOSANT >= 1 )
                     {
                              while ( I != EXPOSANT )
                                    {
                                      RESULTAT=RESULTAT*VALEUR;
                                      I++;
                                    }
     
                              return RESULTAT;
                     }
     
                 if ( EXPOSANT < 0 )
                    {
                              while ( I != -EXPOSANT )
                                    {
                                      RESULTAT=RESULTAT*VALEUR;
                                      I++;
                                    }
     
                              return 1/RESULTAT;
                     }
             }
    } 
     
     
    ////////////////////////////////////////////////////////////////////////////////
    // ENTIER_DANS_TABLEAU : Décomposer un entier dans un tableau
    ////////////////////////////////////////////////////////////////////////////////
    // Entrée :
    //   VALEUR : double
    //   TABLEAU : un double pointeur sur un entier 
    //   TAILLE_TABLEAU : un pointeur sur un entier 
    //
    // Pré-Conditions :
    //   VALEUR >= 0
    //
    // Sortie : 
    //   TABLEAU : un double pointeur sur un entier
    //   TAILLE_TABLEAU : un pointeur sur un entier
    //
    // Post-Conditions :
    //   ...
    ////////////////////////////////////////////////////////////////////////////////
    void ENTIER_DANS_TABLEAU( double VALEUR, double *(*TABLEAU), int *TAILLE_TABLEAU )
    { 
        // On vérifie que VALEUR est une partie entière
        if( VALEUR != floor(VALEUR) || TAILLE_TABLEAU==NULL)
          {
              printf("\nERREUR DANS LA FONCTION ENTIER_DANS_TABLEAU\n   -LA VALEUR QUE VOUS AVEZ ENTRE N'EST PAS UNE PARTIE ENTIERE\n   -LE POITEUR SUR TAILLE_TABLEAU N'EST PAS CORRECTEMENT REFERENCE\n");
          } 
     
     else {
     
                if ( VALEUR == 0 )
                   {
                         (*TABLEAU)   = malloc((*TAILLE_TABLEAU)*sizeof(int));
                         (*TABLEAU[0])= 0                               ;
                   }
     
                if( VALEUR >= 0 )
                  { 
                         *TAILLE_TABLEAU=NOMBRE_DE_DIGITS(VALEUR, 10);
     
                         (*TABLEAU) = malloc((*TAILLE_TABLEAU)*sizeof(double));
     
                         if( TABLEAU==NULL ) 
                           {
                               printf("\nERREUR SUR LE POINTEUR TABLEAU\n");
                           } 
     
                         int J;
                         for ( J=((*TAILLE_TABLEAU)-1) ; J>=0 ; J-- )
                             {
                                 (*TABLEAU)[J] =  floor(VALEUR/PUISSANCE(10, J));
                                   VALEUR     -= ((*TABLEAU)[J])*PUISSANCE(10, J) ;
                             }
                     }
     
     
                 else printf("\nERREUR INCONNUE DANS L'UTILISATION DE LA FONCTION ENTIER_DANS_TABLEAU\n");
          }
    }
     
     
    ////////////////////////////////////////////////////////////////////////////////
    // CONVERTIR VERS LA BASE : Donne la valeur du chiffre dans sa nouvelle base
    ////////////////////////////////////////////////////////////////////////////////
    // Entrée :
    //   VALEUR : entier
    //   BASE : entier 
    //
    // Pré-Conditions :
    //   VALEUR >= 0
    //
    // Sortie : 
    //   RESULTAT : entier
    //
    // Post-Conditions :
    //   ...
    ////////////////////////////////////////////////////////////////////////////////
    double VERS_LA_BASE_DECIMALE( double VALEUR, int BASE )
    {
        VALEUR=floor(VALEUR);
     
        int *TAILLE_TABLEAU=malloc(sizeof(int));
        double *TABLEAU=NULL;
     
        ENTIER_DANS_TABLEAU( VALEUR, &TABLEAU, TAILLE_TABLEAU );
     
        double RESULTAT=0;
     
        int I;
        for ( I=0 ; I<(*TAILLE_TABLEAU) ; I++ )
            {
                double R=RESULTAT;
                RESULTAT = RESULTAT + (TABLEAU[I])*PUISSANCE( BASE, I );
                double P=PUISSANCE(BASE, I);
            }
     
        return RESULTAT;
    }
    UNE REPONSE UTILE : &|| UN PROBLEME RESOLU :

  8. #8
    Membre confirmé
    Homme Profil pro
    amateur
    Inscrit en
    Octobre 2007
    Messages
    731
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Octobre 2007
    Messages : 731
    Points : 460
    Points
    460
    Par défaut
    Donc il n'y a pas moyen d'améliorer la précision ? ni de comprendre pourquoi je ne peux pas entrer de nombre plus grand dans un double que dans un entier ?

    Merci
    UNE REPONSE UTILE : &|| UN PROBLEME RESOLU :

  9. #9
    Membre éclairé
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Points : 842
    Points
    842
    Par défaut
    Citation Envoyé par darkwall_37 Voir le message
    pourquoi je ne peux pas entrer de nombre plus grand dans un double que dans un entier ?
    Parce que le type double est limité aussi !
    Il est en général codé sur 8 octets.
    Il a 1 bit de signe, 11 bits d'exposant, et 52 bits de mantisse.
    Quand tu entres un nombre à virgule très long, il fait une approximation et donc normalement tu n'as pas de problèmes.
    Mais sur les entiers le type double est limité au même point que les types entiers, car il ne peux pas faire d'approximation sur les nombres entiers.
    Voilà pourquoi tu ne peux pas entrer d'entiers plus grands dans un double
    Plus tu pédales moins fort, moins t'avances plus vite.

  10. #10
    Membre confirmé
    Homme Profil pro
    amateur
    Inscrit en
    Octobre 2007
    Messages
    731
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : amateur

    Informations forums :
    Inscription : Octobre 2007
    Messages : 731
    Points : 460
    Points
    460
    Par défaut
    Ok, merci ! Et donc il y a plus ling que le type double m'a t-on dit mais il faut utiliser la librairie GMP. Mais je crois que ce n'est pas très portable. En plus leur site est vraiment très mal fait ! Je vais aller chercher un peu plus.
    UNE REPONSE UTILE : &|| UN PROBLEME RESOLU :

  11. #11
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Pouet_forever :
    Mais sur les entiers le type double est limité au même point que les types entiers, car il ne peux pas faire d'approximation sur les nombres entiers.
    Le type double (avec 52 bits de mantisse) représente exactement l'entier tant que le nombre est inférieur (en valeur absolue) à 2^^53 (~9E15).

    Pour des valeurs supérieures, il représente l'entier avec une approximation qui correspond à la mise à 0 d'un ou plusieurs bits de poids faibles.
    Par exemple, 1E16 sera représenté exactement mais 1E16+1 sera représenté comme 1E16 (perte du lsb)
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. quelques précisions sur VPN et xdsl
    Par maharam dans le forum Dépannage et Assistance
    Réponses: 0
    Dernier message: 23/09/2010, 16h32
  2. quelques précisions sur mysql
    Par karimero dans le forum Débuter
    Réponses: 4
    Dernier message: 27/01/2010, 17h35
  3. Quelques précisions sur html:options collection
    Par weed dans le forum Struts 1
    Réponses: 2
    Dernier message: 19/10/2008, 12h02
  4. Précision sur les types Enum et Set
    Par Djakisback dans le forum Requêtes
    Réponses: 2
    Dernier message: 22/12/2006, 13h36
  5. Quelques "précisions" sur Struts
    Par Atma_ dans le forum Struts 1
    Réponses: 19
    Dernier message: 03/11/2006, 15h20

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