Bug d'opération en langage C
Répondre à la discussion
Page 1 sur 2 1 DernièreDernière
Affichage des résultats 1 à 30 sur 33

Bug d'opération en langage C



  1. #1
    invite468a1524

    Bug d'opération en langage C


    ------

    Bonjour à tous, j'ai un problème avec le résultat d'une opération simple en utilisant le langage C.

    Celui-ci fonctionne :

    Code:
    double a=0;
    a=(1+0.00000000000000000000001)*10000000000000000000;
    printf("%f",a);
    alors que celui-ci donne un résultat exotique :

    Code:
    double a=0;
    a=(1+0.00000000000000000000001)*1000000000000000000000;
    printf("%f",a);
    Comprenez vous ce type de comportement ?

    Merci

    -----

  2. #2
    Dlzlogic

    Re : Bug d'opération en langage C

    Bonjour,
    Tout le problème est de savoir ce que vous cherchez à faire.
    Toute machine travaille en binaire. L'addition et la multiplication répondent à des règles strictes et compliquées.
    La précision d'un double est de 15 chiffres significatifs (de mémoire).
    Pour vous convaincre de tour cela, exécutez le petit code suivant:
    Code:
    int main(int argc, char *argv[])
    {
    
      float a,b;
      a=MAXFLOAT;
      b=MAXFLOAT;
      a-=1.;
      b/=2.;
      if (a==b) printf("Egal\n");
      else printf("Différent\n");
      float c=3.0/7.0;
      if (c == 3.0/7.0) printf("Egal\n");
      else printf("Différent !!\n");
    
      while (!kbhit());
      return 0;
    }
    Et on peut en reparlez.

  3. #3
    invite468a1524

    Re : Bug d'opération en langage C

    Merci, je connais une methode de codage pour les nombres fottants avec un nombre de bit pour le mantisse, un autre pour l'exposant et un bit pour le signe, mais je ne sais pas si c'est le cas ici. La précision peut-elle être augmentée ? J'ai besoin d'au moins 50 chiffres significatifs. En fait, c'est pour un programme de calcul d'intégrale qui fonctionnement parfaitement dans la majorité des cas, mais cette limitation de chiffre significatif m'empeche de calculer une intégrale particuliere dans le domaine que je veux.

  4. #4
    Médiat

    Re : Bug d'opération en langage C

    Il existe des tas de librairie (dont GMP) pour la gestion des nombres sans limitation de précision, cherchez sur le net (Big number library) et choisissez celle qui vous convient le mieux (en fonction de vos besoins et de votre compilateur).

    Voir : http://en.wikipedia.org/wiki/Arbitra...etic#Libraries
    Dernière modification par Médiat ; 18/10/2011 à 20h44.
    Je suis Charlie.
    J'affirme péremptoirement que toute affirmation péremptoire est fausse

  5. A voir en vidéo sur Futura
  6. #5
    invite468a1524

    Re : Bug d'opération en langage C

    Une variable crée à l'aide de ces librairies se manipule de la même façon qu'une variable de type double ou float ? La bibliothèque GMD semble compliqué les opérations sur les variables(je debute en C). Quelles librairies me conseillez vous pour résoudre mon problème d'obtenir des variables à au moins 50 chiffres significatifs.

    Merci

  7. #6
    polo974

    Re : Bug d'opération en langage C

    En C, tu ne peux pas utiliser d'opérateurs ( = + - * / ... ) sur de nouveaux types, donc toute opération doit être récrécrite.
    ex:
    y=a*x+b
    devient par ex:

    // y=a*x+b
    mul(y,a,x);
    add(y,y,b);

    (garde toujours une copie de la ligne d'origine en commentaire...)
    c'est pas très dur à transformer (si tu n'as pas de lignes avec 7 parenthèses imbriquées...).

    il faut aussi initialiser les variables en plus de les déclarer pour leur donner une précision (en passant, en gros 3 digits = 10 bit)...
    et clearer après usage, sinon, dur-dur la mémoire...

    en passant, si tu peux, déclare et initialise tes variables le plus tôt et le moins souvent possible (plutôt dans le main que dans la fonction appelée Xmille fois), ça te fera gagner du temps d'exécution. (les puristes vont avoir les poils qui se hérissent, mais, parfois les variables globales se justifient...)
    Jusqu'ici tout va bien...

  8. #7
    Dlzlogic

    Re : Bug d'opération en langage C

    Bonjour,
    Par curiosité, quel type de calcul nécessite 50 chiffres significatifs ?
    Code:
    double a=0;
    a=(1+0.00000000000000000000001)*10000000000000000000;
    printf("%f",a);
    Quel peut être l'intérêt d'une telle initialisation?
    L'initialisation aurait très bien pu s'écrire
    a=1.E19;
    Est-ce Aimesavouret ne confond pas "nombre de chiffres significatifs" de "domaine de définition" ?
    Par ailleurs le format d'impression %f sans autre précision ne donnera généralement que 6 décimales significatives.

  9. #8
    polo974

    Re : Bug d'opération en langage C

    Citation Envoyé par Dlzlogic Voir le message
    Bonjour,
    Par curiosité, quel type de calcul nécessite 50 chiffres significatifs ?
    ...
    Les programmes de test des librairies de calcul de précision arbitraire...
    Jusqu'ici tout va bien...

  10. #9
    Dlzlogic

    Re : Bug d'opération en langage C

    Pardon, je me suis mal exprimé.
    Ma question était posée dans le cadre d'un calcul numérique d'intégrale.
    J'imagine bien par ailleurs le type de besoin dans un cadre de recherche fondamentale.

  11. #10
    invite468a1524

    Re : Bug d'opération en langage C

    Bonjour, pour répondre à Dlzlogic, vous allez comprendre concrètement l'intérêt.

    Code:
    double tf,a,b,d;
    
    a=1.E-5;
    v=1.E-5;
    d=1.E-40;
    
    tf = ( -v + sqrt(v*v + 2*a*d)  ) / a ;
    
    printf("%f",tf);
    A cause du problème de précision, on a tf = 0. En effet "sqrt(*)" ne donne pas un résultat exacte mais à 15 chiffres significatifs. En fait 15 chiffres significatifs suffit pour tf . C'est le calcul qui doit se faire avec un nombre plus grand de chiffre significatif, 50 par exemple.
    Or tf ne doit pas être nulle pour les calcules qui suivront (il n'est pas négligeable).

    Si vous avez des suggestions pour résoudre ce problème, n'hésitez pas !


    Voila, où j'en suis, j'ai téléchargé et compilé GMP (il me semble très adapté) avec MINGW32 afin de rajouter la bibliothèque à CodeBlocks (windows) .
    J'ai bien dans le répertoire include de mon IDE "gmp.h" et "gmpxx.h". Dans lib, j'ai "libgmpxx.a" et "libgmp.a" .

    Maintenant, si je veux compiler avec :

    Code:
    #include <gmpxx.h>
    #include <gmp.h>
    J'ai un rapport d'erreur sur ces lignes. Dans "Setting" -> "Compiler and Debugger" -> "Linker setting" , j'ai ajouté le libgmpxx.a puis le libgmp.a . Mais ça ne fonctionne pas, toujours la même erreur, j'aurai besoin d'aide à ce niveau, Que dois-je faire de plus pour installer la librairie GMP pour CodeBlocks (ou autres si vous savez que ça fonctionne) ?


    Encore merci !

  12. #11
    Dlzlogic

    Re : Bug d'opération en langage C

    Bonsoir,
    Ce n'est sûrement pas un problème de nombre de chiffres significatifs.
    Comme format de printf, utilisez e plutôt que f. Il y a aussi g, E ou G.
    Choisissez celui dont l'aspect vous plait le plus.

    En d'autres termes, il faudrait une bonne raison pour travailler avec plus que la précision double.
    Il existe aussi en base la précision long double, mais le vous le déconseille vivement.

  13. #12
    invite468a1524

    Re : Bug d'opération en langage C

    Il est vrai que :
    Code:
    printf("%f",tf);
    ne sert ici pas à grand chose car ça ne donne que 6 chiffres significatifs. C'est une erreur, désolé.
    tf est nulle car si on multiplie par exemple par 10^15 (15 chiffres significatifs) alors le résultat est toujours nulle.
    J'aurai du mettre :

    Code:
    printf("%.15f",tf);
    Vous pouvez vérifier, ici tf est nulle strictement.
    Ce n'est pas le "printf(*)" qui m'intéresse mais la valeur de tf qui doit être non nulle.

  14. #13
    invite468a1524

    Re : Bug d'opération en langage C

    Mince, j'ai encore une erreur,
    Code:
    printf("%.15f",tf);
    ne suffit pas forcement, disons pour ce cas :
    Code:
    printf("%.100f",tf);
    Mais le printf(*) n'a pas d'importance, c'est la valeur de tf qui ne doit pas être nulle.
    Normalement tf = 1.69E-16 !

  15. #14
    Dlzlogic

    Re : Bug d'opération en langage C

    Code:
    double tf,a,b,d;
    
    a=1.E-5;
    v=1.E-5;
    d=1.E-40;
    
    tf = ( -v + sqrt(v*v + 2*a*d)  ) / a ;
    
    printf("%f",tf);
    Quand vous aurez déclaré v, et imprimé avec le bon format, vous pourrez constater que tf = 1.07533E-18
    Donc, tf n'est manifestement pas nul.
    Par ailleurs, à moins d'écrire tf = 0.; il est très rare que le résultat d'une opération soit strictement nul.
    "Vous savez, ce n'est pas à un vieux singe qu'on apprend à faire des grimaces". proverbe très utilisé là où il y a des singes.

  16. #15
    invite468a1524

    Re : Bug d'opération en langage C

    Oui, j'ai écrit b au lieu de v dans la déclaration des variables.
    Merci, Dlzlogic j'admire ceux qui ont de l'expérience.

    J'ai donc testé ce code :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    
    {
    
    double tf,a,d,v;
    
    a=1.E-5;
    v=1.E-5;
    d=1.E-40;
    
    tf = ( -v + sqrt(v*v + 2*a*d)  ) / a ;
    
    printf("%.100f",tf);
    
    }
    Même en utilisant %e , j'obtiens toujours 0.00 ...

    Comment avez vous obtenue votre résultat ?
    Avec Xcas j'obtiens 1.69E-16 .

  17. #16
    Dlzlogic

    Re : Bug d'opération en langage C

    Comment avez vous obtenue votre résultat ?
    Exactement avec votre code, en déclarant v et avec print("%g",tf);
    %.100f ne sert à rien.
    Voila mon code
    Code:
    int main()
    {
    double tf,a,b,d;
    
    a=1.E-5;
    double v=1.E-5;
    d=1.E-40;
    
    tf = ( -v + sqrt(v*v + 2*a*d)  ) / a ;
    
    printf("%g",tf);
      system("Pause");
      return 0;
    }

  18. #17
    invite4492c379

    Re : Bug d'opération en langage C

    Je viens d'essayer ton code (compilé avec gcc sous linux, j'ai juste enlevé le system("Pause") et ajouté les includes) et le résultat affiché est 0.

  19. #18
    invite468a1524

    Re : Bug d'opération en langage C

    Je viens de tester votre code, j'ai "0Appuyer sur une touche .."
    Décidément j'ai un problème avec mon compilateur.

    J'ai testé sur deux PC, toujours sur CodeBlocks, quelle compilateur utilisez vous (sur linux peut-être) ?

    D'autres personnes peuvent-ils tester ?

  20. #19
    invite4492c379

    Re : Bug d'opération en langage C

    Allez, je me lance sans filets




    tf = 9.9999999999999999999999999999 99999975000000000000000000E-36

    Ça vous paraît juste ?

  21. #20
    invite4492c379

    Re : Bug d'opération en langage C

    ooops ... il y a une erreur ... mais l'intention y est

    tf = 9.9999999999999999999999999999 99999950000000000000000000E-36

  22. #21
    invite468a1524

    Re : Bug d'opération en langage C

    Excellent photon57, un développement limité très pertinent, initialement l'idée m'étais venue mais je ne l'ai pas retenu dans le cadre de mon programme qui sonde une intégrale pour différents couples (a,v,d) avec d qui n'est pas forcement très inférieure à a et v.
    Mais bon, avec des conditions, c'était faisable quand j'y pense ( dans un cas on utilise la forme développée et dans l'autre la forme originale sans le problème de précision car d est du même ordre de grandeur de a et v).
    Bref, je viens d'arriver à utiliser la librairie GMP. Après des échecs où je trouvais dans les 10^-18, j'ai compris comment on peut faire des calculs d'une très grande précision. Je travaille avec des variables float à 256 bits. J'ai obtenu le résultat :

    Code:
    9.99999999999999984105197967281081153855561304755162923005869713005423081397
    1222e-36
    Ensuite il faut convertir cette variable en variable double afin de l'utiliser dans la suite, en effet 15 chiffres significatifs suffisent pour le résultat, mais ne suffisait pas pour le calcul (on trouvait 0).

  23. #22
    Dlzlogic

    Re : Bug d'opération en langage C

    Bonjour,
    Faites-moi plaisir, rajoutez les 2 lignes suivantes, juste après le printf
    tf*=1.e20;
    printf("%f\n",tf);

  24. #23
    invite4492c379

    Re : Bug d'opération en langage C

    Le code
    Code:
    #include <stdio.h>
    #include <math.h>
    
    
    int main()
    {
      double tf,a,b,d;
    
    
      a=1.E-5;
      double v=1.E-5;
      d=1.E-40;
    
    
      tf = ( -v + sqrt(v*v + 2*a*d)  ) / a ;
    
    
      printf("%g\n",tf);
      tf*=1.e20;
      printf("%f\n",tf);
      return 0;
    compilé avec

    Code:
    $ gcc -lm t.c
    donne à l'éxecution

    Code:
    $ ./a.out 
    0
    0.000000

  25. #24
    Dlzlogic

    Re : Bug d'opération en langage C

    Alors là, j'en reviens pas !

  26. #25
    invite4492c379

    Re : Bug d'opération en langage C

    pour info la version du compilateur :
    Code:
    $ gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/lto-wrapper
    Target: i686-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.5.2-8ubuntu4' --with-bugurl=file:///usr/share/doc/gcc-4.5/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.5 --enable-shared --enable-multiarch --with-multiarch-defaults=i386-linux-gnu --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib/i386-linux-gnu --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.5 --libdir=/usr/lib/i386-linux-gnu --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-gold --enable-ld=default --with-plugin-ld=ld.gold --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
    Thread model: posix
    gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)

  27. #26
    Dlzlogic

    Re : Bug d'opération en langage C

    En fait il s'agit là d'un problème qui me parait fondamental.
    Je travaille sous Windows avec Borland Builder.
    Je suppose que je vais trouver une version de gcc pour windows, et je vous tiens au courant.

  28. #27
    polo974

    Re : Bug d'opération en langage C

    Je ne vois pas de truc bien spécial...
    en gros on ajoute 2e-40 à 1e-5 soit une dynamique d'environ 115 bits difficiles à caser dans un double...
    donc ce petit rien disparait (avant l'appel à la racine carrée)...

    et le résultat sort à 0
    c'est un aspect de la joie des flottants: epsilon passe vite à la trappe.
    Jusqu'ici tout va bien...

  29. #28
    Dlzlogic

    Re : Bug d'opération en langage C

    Oh, ça y est j'ai compris.
    A ma grande honte, je n'avais même pas regardé le code. Je m'étais contenté de le copier et de l'exécuter.
    a=1.E-5;
    double v=1.E-5;
    d=1.E-40;
    tf = ( -v + sqrt(v*v + 2*a*d) ) / a ;
    Mais que vaut 2 * 1.E-80 ?
    2 est entier ? NON ?
    De toute façon on ne situe pas dans un contexte normal, cela n'a pas de sens d'ajouter un nombre E-10 à un nombre E-80, sauf en recherche fondamentale.
    Un résultat = 0 me laisse tout de même perplexe.
    Je crois que j'ai compris
    1- le second terme dans racine est nul, puisque 2 est entier.
    2- sqrt(v*v) = v et de toute façon sqrt (V + epsilon) = sqrt(V) si le rapport entre V et epsilon est sur moins de 15 chiffres significatifs.
    3- v-v = 0
    4- 0/a = 0


    J'ai chargé Gcc, mais je crois que je vais me dépêcher de le supprimer de ma machine, avant de le décompresser, de l'installer et de m'arracher ce qui me reste de cheveux.

  30. #29
    invite4492c379

    Re : Bug d'opération en langage C

    En fait il n'y a rien d'anormal dans dans tout ça. 2*a*d s'évaluera à 2e-45 (le 2 notation entière sera promu en double), ensuite on ajoute le v*v qui s'évalue à 1e-10. Les doubles ont une précision d'à peu près une quinzaine de chiffres v*v+2*a*d donne le même résultat que v*v.

    Les différences résident je pense simplement dans la lattitude que la norme du C laisse aux implémentations.

  31. #30
    polo974

    Re : Bug d'opération en langage C

    Citation Envoyé par Dlzlogic Voir le message
    ...
    Un résultat = 0 me laisse tout de même perplexe.
    Je crois que j'ai compris
    1- le second terme dans racine est nul, puisque 2 est entier.
    non, 2 deviendra 2.0, et cela même au moment de la compilation.
    2- sqrt(v*v) = v et de toute façon sqrt (V + epsilon) = sqrt(V) si le rapport entre V et epsilon est sur moins de 15 chiffres significatifs.
    c'est juste (V + epsilon) = (V) dès lors qu'il y à un rapport de l'ordre de 1015 (ou 249) entre V et epsilon.
    à partir de ce moment, tout est plié. la racine vient après
    3- v-v = 0
    4- 0/a = 0

    J'ai chargé Gcc, mais je crois que je vais me dépêcher de le supprimer de ma machine, avant de le décompresser, de l'installer et de m'arracher ce qui me reste de cheveux.
    Mais, il est bien, gcc...
    Jusqu'ici tout va bien...

Page 1 sur 2 1 DernièreDernière

Discussions similaires

  1. bug ou pas bug?
    Par invitec35bc9ea dans le forum Internet - Réseau - Sécurité générale
    Réponses: 13
    Dernier message: 03/07/2009, 09h54
  2. de langage C en langage assembleur
    Par invite284746c1 dans le forum Électronique
    Réponses: 1
    Dernier message: 14/05/2009, 13h42