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 :

int, unsigned int, et la fonction pow


Sujet :

C

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut int, unsigned int, et la fonction pow
    Bonjour, je suis tombé sur un pb. J'arrive à l'identifier et à le corriger, mais je ne sais pas pourquoi ce que j'ai fait fonctionne. Voici mon programme (archi simple) :

    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
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
     
    int main()
    {
      int n=10,k=1;
      double b=2.,auxb=(b-1.)/b,aux1=pow(b,k);
      double aux2=pow(b,k-n)/(sqrt((1.+auxb*k)*aux1));
     
      printf("aux2 = %f\n",aux2); 
     
      return EXIT_SUCCESS;
    }
    la sortie est

    aux2 = 0.001128
    tout va bien. Maintenant, je me suis dit que k et n étaient > 0 donc je vais les modifier en mettant un unsigned devant (en fait, à terme, j'aurais des unsigned long long int car j'aurais de très grands entiers). Voici mon nouveau prgm (je n'ai que modifié la première ligne du main en y ajoutant un unsigned)

    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
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
     
    int main()
    {
      unsigned int n=10,k=1;
      double b=2.,auxb=(b-1.)/b,aux1=pow(b,k);
      double aux2=pow(b,k-n)/(sqrt((1.+auxb*k)*aux1));
     
      printf("aux2 = %f\n",aux2); 
     
      return EXIT_SUCCESS;
    }
    et là, la sortie est

    aux2 = inf
    ce qui ne vas pas du tout. Donc pour corriger je dois faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    double aux2=pow(b,(double) k-n)/(sqrt((1.+auxb*k)*aux1));
    Quand j'affiche k-n il me renvoie -9. Certes, ce sont des unsigned donc le problème vient de là (enfin je pense). Pourquoi la conversion de l'entier k-n en double n'est-elle pas automatique ? man pow me dit que la fonction pow prend deux doubles en entrée.

    Merci.

  2. #2
    Membre régulier Avatar de Dev-FX
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2006
    Messages : 94
    Points : 93
    Points
    93
    Par défaut
    Salut,

    Tu touches ici le grand probleme du langage C (ou limites) ,il est limité a (2^32) - 1, si tu veux allez plus loin il faut faire un effort !!
    Essaie avec la fonction factorielle par exemple .
    Sinon , je parle pas de la manipulation des chaines de caracteres.......

    Merci .

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par salseropom
    Quand j'affiche k-n il me renvoie -9. Certes, ce sont des unsigned donc le problème vient de là (enfin je pense). Pourquoi la conversion de l'entier k-n en double n'est-elle pas automatique ? man pow me dit que la fonction pow prend deux doubles en entrée.
    Ben oui. tu fais une différence entre 2 unsigned, et celle-ci est négative. Résultat, un unsigned énorme !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    #include <stdio.h>
     
    int main(void)
    {
       unsigned int n=10,k=1;
       printf("k-n = %u\n", k - n);
     
      return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    k-n = 4294967287
     
    Press ENTER to continue.
    Cette valeur est convertie automatiquement en double par pow() et c'est le drame.

    Soit tu laisses int, soit tu castes en int avant de passer à pow() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      double aux2=pow(b,(int)(k-n))/(sqrt((1.+auxb*k)*aux1));
    Pas de Wi-Fi à la maison : CPL

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Dev-FX
    Tu touches ici le grand probleme du langage C (ou limites) ,il est limité a (2^32) - 1, si tu veux allez plus loin il faut faire un effort !!
    Essaie avec la fonction factorielle par exemple .
    Sinon , je parle pas de la manipulation des chaines de caracteres.......
    Portnawak...
    Pas de Wi-Fi à la maison : CPL

  5. #5
    En attente de confirmation mail
    Inscrit en
    Octobre 2006
    Messages
    123
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 123
    Points : 112
    Points
    112
    Par défaut
    boulalalalala.... c'est du C c'est pas du MatLab... j'rigole...il faut savoir que le C est très "strict"...donc si une fonction te demande un double, ne lui mets pas un unsigned int...

    Exemple concret : Imagine tu es au resto avec ta femme, tu commandes des carottes RAPEES et le serveur t'apporte une carotte entiere toute pleine de terre, si tu la laves et la rapes tu peux la manger mais ce n'est pas ce que tu attendais de la part du resto???!! Eh ben là c'est pareil, la fonction te demande un double donc donne-lui un double...c'est logique,nan?

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Ben oui. tu fais une différence entre 2 unsigned, et celle-ci est négative. Résultat, un unsigned énorme !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    #include <stdio.h>
     
    int main(void)
    {
       unsigned int n=10,k=1;
       printf("k-n = %u\n", k - n);
     
      return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    k-n = 4294967287
     
    Press ENTER to continue.
    Cette valeur est convertie automatiquement en double par pow() et c'est le drame.

    Soit tu laisses int, soit tu castes en int avant de passer à pow() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      double aux2=pow(b,(int)(k-n))/(sqrt((1.+auxb*k)*aux1));

    Salut, oui je m'attendais à ce genre d'explication. Mais je ne comprends pas très bien le fonctionnement du compilo :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    k-n = 4294967287
     
    Press ENTER to continue.
    donc si je cast k-n en double

    pourquoi aurai-je -9 (ce que je veux car je rappelle que k==1 et n==10) et non 4294967287 ? Est-ce que le cast en double, transforme AVANT d'effectuer le calcul k et n en double (ce que je pense vu lesrésultats) ?

    Merci.

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par salseropom
    Salut, oui je m'attendais à ce genre d'explication. Mais je ne comprends pas très bien le fonctionnement du compilo :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    k-n = 4294967287
     
    Press ENTER to continue.
    donc si je cast k-n en double

    pourquoi aurai-je -9 (ce que je veux car je rappelle que k==1 et n==10) et non 4294967287 ? Est-ce que le cast en double, transforme AVANT d'effectuer le calcul k et n en double (ce que je pense vu lesrésultats) ?
    Ce que tu as fait a converti un des éléments en double, ce qui a automatiquement indiqué au compilateur de convertir tous les éléments de l'expression en double avant le calcul, conformément aux regles de promotion du langage C.

    Mais c'est lourdingue, c'est pourquoi le simple cast du résultat en int suffit comme je l'ai indiqué. La conversion int -> double est automatique car le prototype de la fonction a été fourni.
    Pas de Wi-Fi à la maison : CPL

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Mais c'est lourdingue, c'est pourquoi le simple cast du résultat en int suffit comme je l'ai indiqué. La conversion int -> double est automatique car le prototype de la fonction a été fourni.
    OK, je comprends mieux. Mais j'ai de très grands nombres donc j'ai peur que la conversion en int me retourne un pb car il se peut que je dépasse MAX_INT. Je me suis donc dit que passer en double me laissait plus de marge.

    Merci pour tous ces renseignements.

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par salseropom
    OK, je comprends mieux. Mais j'ai de très grands nombres donc j'ai peur que la conversion en int me retourne un pb car il se peut que je dépasse MAX_INT. Je me suis donc dit que passer en double me laissait plus de marge.
    Déjà, il y a long et [C99] long long si nécessaire. Mais attention à ne pas exploser la fonction pow(). Tu as vu qu'on a vite fait de partir en INF avec un simple unsigned int.

    Garder aussi en tête qu'avec les doubles, on augmente la plage, mais c'est au prix de la perte de précision.
    Pas de Wi-Fi à la maison : CPL

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Pour que tu comprennes l'un des problèmes liés à l'utilisation des (unsigned) types, il faut savoir que, quelque soit le type que tu décide de présenter en tant que "unsigned" (et pour autant, nous nous comprenons bien, que ca aie un sens de le faire) que la représentation en mémoire est exactement pareille qu'il s'agisse d'un unsigned ou non...

    Seule "l'interprétation" de la valeur change en fonction de si c'est considéré comme non signé ou comme signé.

    Je vais, pour te l'expliquer, me baser sur un caractère de 8 bits, le tout, en sachant qu'un caractère peut ne pas être forcément codé sur 8 bits, et que le raisonnement est exensible aux autres types qui acceptent d'être considéré comme signés et comme non signés.

    Nous avons donc 8 bits, qui permettent de représenter, comme chacun le sait, 255 possiblités (2^8)-1=255
    En mémoire, cela prend la forme de
    où b7 est considéré comme "le bit de poids fort" (celui qui a la plus grosse valeur). et b0 comme "le bit de poids faible"

    Le gros problème, c'est que sur ces 8 bits, il n'y a aucun moyen de désigner le signe " - " (vu que les seuls sitgnes sont... 0 et 1)

    Enfin, si, il y en a un... mais il passe par le sacrifice d'un bit, qui aura alors comme signification "0->le nombre est positif, 1->le nombre est négatif"

    Mais il y a deux autres problèmes:
    • il est toujours plus facile d'effectuer une addition qu'une soustraction (rappelle toi le temps béni où tu étais en primaire, et ou le prof te disait, pour te faire trouver le bon résultat à 11-3 "voyons, salseropom, 3+ combien font 11 ")
    • 10000001, ca ne vaut pas "-1"

    Les deux problèmes sont en fait liés, parce qu'historiquement parlant, il était plus facile de travailler avec une addition qu'avec une soustraction au niveau du processeur, et qu'il fallait bien que 7-4 donnne un résultat correct

    Par contre, l'addition ne pose pas problème, et il y a une autre chose très facile à faire qui est d'inverser la valeur d'un bit.

    Les concepteurs de l'époque se sont donc dit "mais, soustraire, cela revient à ajouter l'opposé"... et ont donc décidé d'inverser la valeur des bits.

    De cette manière
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    10000001 
    devenait
    01111110
    et était appelé "complément à 1"

    Sauf que... 1-1=...0, alors qu'ici, si on additionne les deux, on obtient 11111111... qui vaut...255

    Pour revenir à 0, ce qu'il manquait, c'est... 1 (on se retrouve alors avec 100000000, mais comme il n'y a de la place que pour 8 bits, le 1 tombe "aux oubliettes" (meme s'il est récupéré par un flag ailleurs dans le processeur)) et la valeur obtenue prenait, logiquement le nom de "complément à 2"

    Le résultat des courses, c'est que, quand tu demandes de faire 1-10 à l'ordinateur, il va
    • calculer le complément à deux de 10 (00001010==>11110101 +1==>11110110)
    • additionner 1 au complément à deux (1+11110110==>11110111)
    • interpréter le résultat...

    Sauf que, 11110111, si on travaille en mode "signé", ca indique... un nombre négatif...

    Donc, pour obtenir la valeur absolue de ce nombre, il faut... en calculer le complément à 2...

    Ce qui donne: 11111100-->00001000+1-->00001001=...9 (donc on a bel et bien -9) Mais qui vaudrait tout aussi bien 247 si l'on décidait de recommencer à travailler en "unsigned"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par koala01
    Nous avons donc 8 bits, qui permettent de représenter, comme chacun le sait, 255 possiblités (2^8)-1=255
    Pourquoi -1 ? Les valeurs possibles vont de 0 à N-1, mais il y a N valeurs... Un objet de 8 bits peut donc bien prendre 2^8 valeurs, soit 256, de 0 à 255.
    *10000001, ca ne vaut pas "-1"
    Ca pourrait sur une architecture 'sign + magnitude', soit une des 3 représentations possibles des nombres signées en C, avec complément à 1 et complèment à 2.
    Pas de Wi-Fi à la maison : CPL

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par koala01
    Nous avons donc 8 bits, qui permettent de représenter, comme chacun le sait, 255 possiblités (2^8)-1=255
    Donc 1 bit, 1 possibilité? Tu confonds le nombre de possibilités et la valeur maximale en unsigned (qui est inférieure de 1 car 0 est une possibilité).

    Pour l'aspect historique... Le choix entre une representation en grandeur et signe, complément a la base moins un (a 1 en binaire ou a 9 en decimal) ou complément a la base (a 2 en binaire ou a 10 en decimal) n'a ete reellement fixe qu'assez tard. Le complément a un a quasiment complètement disparu -- le seul cas que je connais ou il est encore utilise est par pure compatibilité; et si j'admets que je n'ai jamais compris les raisons qui ont pousse a son utilisation, il me semble certain que ce n'est pas l'ignorance des autres représentations. Les representations grandeurs et signe sont toujours parfois utilisees -- dans les packages bignum, dans les flottants, dans les processeurs ayant des instructions decimales -- et une quatrieme representation -- un simple offset -- l'est pour les exposants dans les flottants.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

Discussions similaires

  1. Transformer (int année, int mois, int jour) en millisecondes
    Par Logic_613 dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 24/04/2012, 11h08
  2. Réponses: 1
    Dernier message: 15/02/2007, 17h32
  3. Conversion int en string pour paramatre fonction
    Par Aliveli dans le forum Visual C++
    Réponses: 9
    Dernier message: 10/10/2006, 21h56
  4. int, unsigned char ou bool ?
    Par BNS dans le forum C++
    Réponses: 10
    Dernier message: 21/06/2006, 21h59
  5. [WMI] Variant de type Unsigned Int 64 ...
    Par phplive dans le forum API, COM et SDKs
    Réponses: 3
    Dernier message: 09/05/2006, 20h15

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