Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

comparaison de flottants

209 réponses
Avatar
Emmanuel
bonjour tout le monde,

une question de vrai débutant :

Avec le programme essai.c suivant

int main(void) {
return ((1.7 + 0.1) == 1.8) ? 1 : 0;
}

j'obtiens :

$ gcc -Wall -o essai essai.c; ./essai; echo $?
1

Avec le programme essai.c suivant

int main(void) {
float x;
x = 1.7;
return ((x + 0.1) == 1.8) ? 1 : 0;
}

j'obtiens :

$ gcc -Wall -o essai essai.c; ./essai; echo $?
0

Pourtant, le programme

#include <stdio.h>
int main(void) {
float x;
x = 1.7;
printf("%f et %f\n", 1.7 + 0.1, x + 0.1);
}

affiche :
1.800000 et 1.800000

Apparremment, 1.7+0.1 et x+0.1 sont égaux ; j'imagine qu'il s'agit d'un
problème de représentation des flottants en machine mais j'aimerais bien
avoir une confirmation ou une infirmation (et une explication, si possible).

Merci par avance.

Emmanuel

10 réponses

Avatar
Samuel DEVULDER
Vincent Lefevre a écrit :

Quand tu parles d'exposant binaire (et pas décimal), tu signifies
quelque chose qui s'écrit en base 2, uniquement avec des 0 et des 1. Bon
ton expression était incorrecte, non conforme, bref un bug.



Arf! Dans la norme: "binary exponent part".




Désolé. Sur http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf je
n'ai pas trouvé "binary exponent part" dans la description de printf
dont je re-imprime ici la partie qui nous concerne:

a,A
A double argument representing a floating-point number is converted in
the style [−]0xh.hhhh p±d,where there is one hexadecimal digit (which is
nonzero if the argument is a normalized floating-point number and is
otherwise unspecified) before the decimal-point character and the number
of hexadecimal digits after it is equal to the precision; if the
precision is missing and FLT_RADIX is a power of 2, then the precision
is sufficient for an exact representation of the value; if the precision
is missing and FLT_RADIX is not a power of 2, then the precision is
sufficient to distinguish values of type double,except that trailing
zeros may be omitted; if the precision is zero and the # flag is not
specified, no decimal-point character appears. The letters abcdef are
used for a conversion and the letters ABCDEF for A conversion. The A
conversion specifier produces a number with X and P instead of x and p.
The exponent always contains at least one digit, and only as manymore
digits as necessary to represent the decimal exponent of 2.

Relis la fin du paragraphe: The exponent always contains at least one
digit, and only as manymore digits as necessary to represent the
*decimal exponent of 2*.

Je n'insisterais pas plus. (Le sujet n'en mérite pas la peine.)


sam.
Avatar
Antoine Leca
Samuel DEVULDER écrivit :
Ok c'est plus clair à présent, sauf que je ne vois pas pourquoi on a
laissé un choix arbitraire pour ce 1er digit.



Comme tu le dis si bien, c'est arbitraire.

Maintenant, il existe un monde avant 1999, et en particulier dans ce
monde réel il y a des implémentations (hardware) où les flottants sont
représentés en base 10, et d'autres (en particulier chez IBM SJMSB) en
base 16! Et il aurait été stupide de la part du comité C de décider
arbitrairement pour une représentation qui aurait été incompatible avec
l'existant, ou qui aurait arbitrairement compliqué les implémentations
existantes : imagine le cas où ta machine cause la base 16 mais ce que
te montre %a est différent d'un vidage mémoire... à cause d'un décalage
de 1 ou 2 bits.


de toute façon la base de l'exponentielle est 2 (p=pow(2,.)),



Bin non justement, le fond du problème est bien là.


Antoine
Avatar
Antoine Leca
Vincent Belaïche a écrit :
Dans la documentation de emacs calc les notations resemblant à à %f, %e,
et %g sont repsectivement appelé fix, scientific, et engineering.



[ couic ]

Le mode ingénierie et ses puissance multiple de trois, autrement dit
utilisant la base 1000, je connais (les calculatrices HP et TI de ma
jeunesse l'avaient aussi) ; mais je ne vois pas le rapport avec %g.


Par contre, je vois pas mal de similitude entre ce mode et la discussion
sur l'ambiguïté formelle concernant %a. Jusqu'ici, j'ai lu deux
propositions différentes sur la norme à suivre pour %a :
- forcer le premier chiffre à 1
- forcer le premier chiffre entre 8 et 15, qui correspond à la
« logique » de l'expression m×B^e avec ½ <= m < 1 : en base 16, cela
oblige à écrire m comme 0,c... et le chiffre c sera entre 8 et 15

Ce qui est rigolo (à mon sens), c'est que la fameuse notation ingénierie
appliquée à l'hexadécimal au lieu de la base 1000, serait une troisième
proposition : faire que l'exposant soit divisible par 4 ! Et là, on a
besoin de tous les chiffres entre 1 et 15 pour la partie entière de la
mantisse, de la même manière qu'avec la notation ingénierie les chiffres
avant la virgule peuvent être entre 1 et 999.


Et un dernier pour la route : un équivalent en hexadécimal du mode
ingénierie va immanquablement demander d'utiliser la base 1024, histoire
d'utiliser le kibi, Ki, Mi et autres gibi ;-) Sauf que, on a là une
quatrième convention, car si 1024 est pas une puissance de 2, ce n'est
pas une puissance de 16 : donc le décalage va être encore différent, et
on obtiendra une nouvelle règle !
Dommage que le 1er avril vienne juste de passer, je sens qu'on a là un
bon début pour entreprendre une RFC-gag...


Antoine
Avatar
Antoine Leca
Samuel DEVULDER a écrit :
Vincent Lefevre a écrit :
Dans l'article <4bb85925$0$30018$,
Samuel DEVULDER écrit:

Vincent Lefevre a écrit :



"Exposant binaire" signifie que cela donne 2^e. Je ne parle pas de
l'écriture de l'exposant, mais de sa sémantique.





Ah ok. Il faut préciser car sur les docs (rares) décrivant %p, toutes
parlent d'exposant décimal et pas binaire.



Un conseil: évite ces docs et réfère-toi à la norme C ISO.



Pourquoi? Parce que ca ne va pas dans ton sens? Non merci.



C'est un conseil ; tu es libre d'en faire cas ou pas.

Cependant, afin de t'aider à discerner un peu plus, je vais en rajouter
un peu sur le commentaire de Vincent.

À la suite du texte ci-dessus, tu écrivis
::> Insister sur l'exposant *binaire* comme tu l'a fait est très
::> surprenant par rapport à la littérature.

Vincent est un universitaire; et qui plus est, un universitaire qui
travaille précisément sur ce sujet des nombres flottants, et qui publie.
Je ne t'apprend pas que dans le monde universitaire, « la littérature »
se réfère à l'ensemble des publications sur un sujet, et une partie
importante du travail de recherche est justement de trier dans « la
littérature » le bon grain de l'ivraie, pour ensuite intégrer dans ses
propres publications (par référence) la « bonne » littérature.

Je ne sais pas si dans ta pensée, le mot littérature ci-dessus avait ce
sens ; mais je suis à peu près sûr que Vincent, lui, l'a lu dans ce
sens; et donc il t'a donné un conseil qui a d'autant plus de valeur
qu'il a une longue expérience de cette fameuse littérature à laquelle tu
faisais référence.


Du reste parler d'exposant décimal pour dire qu'on l'affiche en base
dix est ce qu'on appelle parler du français ou un anglais correct.



Certes. Mais comme il s'agit tout autant d'un exposant binaire
(puissance de deux qui modifie la mantisse), il y a ambiguïté.
Une autre ambiguïté est que le mot exposant peut signifier soit la
valeur entière, soit le résultat après exponentiation. Enfin, là c'est
ma lecture du sujet, peut-être que je me trompes ici.

Les documents auxquels tu fais référence insistent (et je le comprend
tout-à-fait, car ce n'est pas évident, surtout du fait du contexte) sur
la forme --en base 10, donc-- de la valeur de l'exposant ;
la position de Vincent, et je le comprend comme étant la vision des
spécialistes du domaine (dont je ne suis pas), est de mettre plus
d'emphase sur la différence avec le format %e (celui des calculatrices
scientifiques), en particulier le choix de la base.


Antoine
Avatar
Samuel DEVULDER
Vincent Lefevre a écrit :

Que tu le veuilles ou non, un grand nombre de personnes considèrent ce
qui est posté dans les groupes de discussion (tout comme sur le web)
comme des enseignements. Et ils n'ont pas forcément la possibilité
de distinguer le vrai du faux, surtout si les idées fausses sont
répandues, que ce soit sur Usenet, sur le web et même dans des docs
réputées sérieuses, voire plus ou moins officielles.

Donc quand on trouve une erreur, on la signale.



Et même mieux: on fourni une meilleure version.

Encore faut il que ce soit une vraie erreur. Un bout de code juste pour
C89 pourra être considéré comme une erreur en C99. Alors où se situe
l'erreur? Dans le code ou dans le fait que le contexte du code ne soit
pas précisé?

L'erreur vient peut être de celui qui attribue un context hyper
spécifique (C99, sizeof(long)==8) sur un truc où rien n'est précisé?

Comme je le dis un vrai bon message ne se contentera pas de dire "code
faux" sans autre forme de procès mais dira: "ce code ne passe pas sous
C99 car ceci/cela. On préfèrera utiliser la version suivante qui règle
ce défaut: <exemple corrigé>".


un cours de maths contenait des pseudo-démonstrations approximatives,
et qu'on demande ensuite aux étudiants de faire des vraies
démonstrations rigoureuses sur leurs copies.





Et pourtant nombre de choses incomplète laissées "en exercice" à l'élève
existent.



Mais quand quelque chose est incomplet, on est suffisamment clair et
on indique ce qui est incomplet.



Si on est professeur (ou qu'on adopte un ton professoral), oui. Mais ça
n'est pas ma position.

sam.
Avatar
Manuel Pégourié-Gonnard
Samuel DEVULDER scripsit :

C'est pas vraiment ma position. Il n'est pas question d'enseigner quoi
que ce soit.



Il n'est peut-être pas question réellement d'enseigner, mais force est
de constater que ce qui est écrit ici est utilisé comme ressource
d'apprentissage, que soit soit directement en lurkant, ou par le biais
d'une recherche google ultérieure. Et, comme l'ont déjà fait remarquer
d'autres contributeurs, rarement avec le discernement et le reagrd
critique qui conviendrait.

A la lecture je constate que tu places ton point de vue sur l'axe
enseignant->élève. La question sous-jacente est: est-ce que ce groupe
sert à enseigner le C par des profs de fac ou a discuter entre
praticiens du C? A priori j'ai cru qu'on avait affaire à des gens qui
codent effectivement en C et veulent partager leur expériences et
problèmes. J'ai peut être tord... j'avais pas vu que c'était réservé aux
profs. Je comprends mieux l'aversion constatée envers tout ce qui porte
le mot "industriel" de certain :) J'ai empiété quelques prés-carrés. Désolé.



À titre personnel, ce que je cherche en lurkant ici, par rapport à la
lecture de tel ou tel bouquin ou polycopié de cours, c'est des échanges
de point de vue sur la pratique du C « dans la vraie vie », que ce soit
dans du logiciel libre ou des applications industrielles sur
plate-formes diverses. Ça permet aussi d'observer les accords et
désaccords pour se faire une opinion sur ce qui relève de la correction
du code ou de goûts personnels. Ça donne aussi plus de relief qu'un
cours où les choses seront présentées de façon uniforme et systématique.

Oui j'y vais fort avec des mots tels que "intégristes"... En fait, c'est
parce qu'il y a un une similitude de comportement et un rejet du point
de vue de l'autre qui sont indéniables entre les deux. La rigueur c'est
bien mais pas en toute circonstances (on est pas chez les amishs!). Il
faut savoir rester pragmatique.



J'ai l'impression que c'est justement le pragmatisme et l'expérience
qui poussent la plupart des contributeur réguliers à :
- respecter la norme autant que possible ;
- quand la norme n'est pas respectée, préciser les hypothèses faites,
histoire de savoir dans quelles circonstances le code en question est
correct, et dans lequelles il ne l'est plus.

Emmanuel ne cherchait pas je crois un
cours sur la portabilité de l'usage de l'union ou du sizeof(long) mais
voir en quoi ses deux doubles diffèrent.



Oui, mais il n'est pas le seul à lire les réponses, qui seront lues
notament hors contexte via google.

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Avatar
Antoine Leca
[ Titre modifié. ]

Marc Espie écrivit :
le 05/04/2010 à 17:22, Marc Espie a écrit dans le message
<hpcv7l$31ho$ :

(bon, a cote, usenet is dying, c'est pas les 3 dinosaures qui trainent
encore ici qui vont se faire avoir...)





Chouette, mon piege a (semi)lurkers a fonctionne :)



C'était sûr que cela fonctionnerait : ce doit être la première fois de
l'année qu'il y a (largement) plus de 20 messages en moins d'une
semaine; et comme il y a dans ce groupe largement plus de lecteurs que
de messages, tu pouvais être sûr que les fureteurs iraient fouiller
jusqu'au fin fond du sous-fil, comme des gourmands qu'ils sont :-).


Antoine
Avatar
Vincent Lefevre
Dans l'article <4bbb0640$0$8300$,
Samuel DEVULDER écrit:

Vincent Lefevre a écrit :

> Que tu le veuilles ou non, un grand nombre de personnes considèrent ce
> qui est posté dans les groupes de discussion (tout comme sur le web)
> comme des enseignements. Et ils n'ont pas forcément la possibilité
> de distinguer le vrai du faux, surtout si les idées fausses sont
> répandues, que ce soit sur Usenet, sur le web et même dans des docs
> réputées sérieuses, voire plus ou moins officielles.
>
> Donc quand on trouve une erreur, on la signale.

Et même mieux: on fourni une meilleure version.



C'est pour cela que j'avais indiqué %a.

Encore faut il que ce soit une vraie erreur. Un bout de code juste pour
C89 pourra être considéré comme une erreur en C99.



C'est très rare.

Alors où se situe l'erreur? Dans le code ou dans le fait que le
contexte du code ne soit pas précisé?



Quand on ne précise pas le contexte, c'est celui de la norme C ISO.
La seule norme C est actuellement la version de 1999 (a.k.a. C99).
C89 n'est plus une norme, même si on peut en parler...

L'erreur vient peut être de celui qui attribue un context hyper
spécifique (C99, sizeof(long)==8) sur un truc où rien n'est précisé?



Si on ne précise pas sizeof(long), il faut considérer toutes les
possibilités, surtout celles existantes en pratique (il faudrait
aussi considérer les bits de padding éventuels, le cas CHAR_BIT
différent de 8...).

--
Vincent Lefèvre - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Avatar
Emmanuel
Quand on poste ici, on ne s'adresse pas uniquement à l'OP.
Celui-ci n'avait d'ailleurs même pas donné l'architecture
et l'OS de sa machine.



$ uname -a
Linux *** 2.6.27-9-generic #1 SMP *** i686 GNU/Linux

--
Emmanuel
Avatar
Jean-Marc Bourguet
Samuel DEVULDER writes:

L'erreur vient peut être de celui qui attribue un context hyper spécifique
(C99, sizeof(long)==8) sur un truc où rien n'est précisé?



Hyper-spécifique? Le type qui charge un Linux grand public pour voir pour
un processeur pas trop obsolète a une chance non négligable de se retrouver
dans cet environnement.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org