Forum Programmation.c Probleme de précision

Posté par  (site web personnel) .
Étiquettes : aucune
0
1
avr.
2006
Bonjour !

J'ai un petit probleme: je finit le debuggage d'un bout de soft (GPL bien sur) qui contient entre autre un module aidant a choisir une résistance (pour l'electronique: on entre la valeur de resistance que l'on veut et il renvoie le code couleur qui correspond).

Les resistances sont codées (dans la version la plus simple) comme deux digits suivis d'une puissance de 10. Donc j'utilise beaucoup de divisions/multiplications par des puissances de 10. Actuellement, mon code est comme cela (toutes les variables sont des "double"):

exponent=floor(log10(R))-1;
first_two_digits=floor(R/pow(10,exponent));

Si R=1, alors on devrait avoir exponent=-1 et first_two_digits=10 afin de dire R=10*10^-1. Sur Linux/ppc, mon code fonctionne parfaitement. Sur intel, j'ai bien exponent=-1 mais first_two_digits=9. J'ai donc essaye de faire calculer la meme chose en dur, et si je fait floor(R/0.1) avec R=1, j'obtient 9 (ce qui signifie que sur intel, 1/0.1=9.9999999999... au lieux de 10.

C'est assez embetant, surtout que j'ai essayé plein de choses: recoder en float, forcer des transtypages (double) un peu partout, rien n'y fait...

Une idée ? (portable si possible, mes cibles sont ppc/intel/sparc sous linux/osx/windows/solaris)

Mathias
  • # Quel compilateur sur quelle plateforme ?

    Posté par  . Évalué à 1.

    • [^] # Re: Quel compilateur sur quelle plateforme ?

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

      sous Intel: gcc4.0.1 sous Linux 2.6.12 (Mandriva 2006 pour i586) et gcc3.4.1 sous Linux 2.6.8 (Mandrake 10.1)
      sous ppc: gcc3.4.1 sous Linux 2.4.xx, c'est une mandrake 10.1 installee dans un chroot de mandrake 9.1 (c'est tordu, mais c'est parce que la mandrake 10.1 que j'avais installee a cote de la 9.1 sur mon cube ne parvenait pas a fonctionner avec les peripheriques ubs style clavier et souris).

      En fait, je viens aussi de trouver cet article sur le meme genre de sujet:
      http://www2.hursley.ibm.com/decimal/

      Comme le dit ton second lien, il y a un probleme fondamental a faire de l'arithmetique decimale pour des chiffres [1;0]: la representation binaire ne correspond pas a un chiffre parfaitement precis (ie: nombre limites de chiffres significatifs). Donc avec mes floor(), je ne parviens pas a retrouver ce a quoi je m'attend.

      La solution, c'est de faire (un peu comme dit dans ton dernier lien): R=R*1.001 . Puisque ensuite j'utilise une notation style DD.10^E, ajouter un millieme est largement suffisant (ce millieme disparait des que j'ai calcule DD et E) et a l'avantage d'etre tres simple. (la solution "theorique" proposee dans ton lien suppose que l'on connait deja la precision souhaitee, chose que je ne connais pas a ce point puisque je la cherche...)

      En tout les cas, merci beaucoup et bravo !

      Mathias
      PS: par contre, le miracle c'est que mon powerpc ait pu passer mes cas tests sans problemes... a creuser lundi!
      • [^] # Re: Quel compilateur sur quelle plateforme ?

        Posté par  . Évalué à 1.

        Merci de ta réponse. Ton lien aussi est très intéressant.
      • [^] # Re: Quel compilateur sur quelle plateforme ?

        Posté par  . Évalué à 0.

        Comme le dit ton second lien, il y a un probleme fondamental a faire de l'arithmetique decimale pour des chiffres [1;0]: la representation binaire ne correspond pas a un chiffre parfaitement precis (ie: nombre limites de chiffres significatifs).

        Plus généralement (et plus exactement), il y a un probleme fondamental à faire de l'arithmetique décimale sur les ordinateurs utilisant une représentation binaire.
        Comme expliqué sommairement dans le premier lien de mmMMOoooOMMmm, sur un ordinateur utilisant en interne des puissances de 2 pour représenter les nombres flottants, aucune puissance négative de 10 ne peut être exactement représentée (i.e. 0,1 ou 0,000001 par exemple). Les calculs flottants sur ordinateur ont une part d'imprécision qu'il faut savoir maîtriser (ce que je ne prétends pas). Le langage C suit la norme IEEE754 sur l'arithmétique flottante (cf. annexe F de la norme C); cette dernière est indépendante de tout langage ou matériel (c'est justement son intérêt) et, pour information, le C n'est pas le seul langage à l'utiliser (Java aussi, et à mon avis bien d'autres...).

        Pour des informations beaucoup plus précises et complètes que ce que j'ai pu écrire au-dessus, mais néanmoins plus compréhensibles, sur ces calculs flottants et en particulier sur la norme IEEE754, lire l'article "What every computer scientist should know about floating-point arithmetic" de David Glodberg, publié dans l'ACM, et disponible en ligne à http://portal.acm.org/citation.cfm?doid=103162.103163 . Il s'agit d'un article très clair, et souvent référencé. C'est devenu ma référence dans le domaine ;) Plutôt que de te le résumer dans ce post, au risque de dire des dizaines d'âneries, je préfère te donner le lien (je viens même de voir que c'est le premier article référencé sur la page du groupe de travail de la norme IEEE754 http://grouper.ieee.org/groups/754/ !).

        Je viens de tomber (suite aux liens précédents) sur http://grouper.ieee.org/groups/754/faq.html#binary-decimal qui répond à ta question ;), et renvoie à une FAQ qui traite entièrement du calcul décimal (mais sur une autre norme, semble-t-il)

        Pour revenir au C, voir aussi la FAQ du newsgroup comp.lang.c, qui contient un chapitre dédié au calcul flottant: http://c-faq.com/fp/index.html .

        Si ça n'étanche pas ta soif de savoir, tu peux lire l'annexe F de la norme C, et la documentation de ton comilateur (cf. l'annexe J.3.6 de la norme qui liste les points sur lesquels une implémentation C doit documenter ses choix).

Suivre le flux des commentaires

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