OVH Cloud OVH Cloud

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
Jean-Marc Bourguet
Samuel DEVULDER writes:

On attends tous la révision *Vincent* de la norme.



Surprise! les normes ont des défauts. Les plus graves sont corrigés (le
troisième jeu de révision de C99 date de 2007, je doute qu'il y en ai un
autre avant la publication de C1X), quand on s'en rend compte, que ce n'est
pas trop invasif, et qu'on se met d'accord sur la correction. Mon
impression est qu'ici le problème est tellement peu grave que la correction
en serait laissée à l'éditeur (comme les fautes d'orthographe et les
incohérences de typographie ne créant pas d'ambiguité) et jamais publiée
dans un TC. Ça ne m'étonnerait pas du tout que Vincent ait connaissance de
problèmes techniques plus graves concernant les nombres à virgule
flottante.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Erwan David
Samuel DEVULDER écrivait :


Tu devrais aller voir de voir du coté d'ADA (et son cheval *sic*), ou
mieux, essaye de voir du coté caml, haskell etc..




Attention tu mélanges des langages à typage plus moins for, des langages
à inférence de type, etc...
(en CAML on ne met pas le type parceque c'est le compilo qui calcule le
type le plus général applicable à l'expression).

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
Jean-Marc Bourguet
Samuel DEVULDER writes:

Vincent Lefevre a écrit :

Donc contrairement à ce qu'affirme Samuel, ce n'est pas le reste
du monde qui utilise une ABI 32 bits.



Je n'ai pas dit cela. J'ai dit "il n'y a pas que MSVC" qui soit resté avec
sizeof(long)==4. N'inverse pas mes propos STP (déjà que tu inverses la
définition de strtod et printf..)

sam (renversant!)



Qui donc est-ce qui a écrit:

Date: Wed, 07 Apr 2010 09:19:56 +0200
From: Samuel DEVULDER
User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
Message-ID: <4bbc320c$0$22387$
NNTP-Posting-Date: 07 Apr 2010 09:19:42 MEST
NNTP-Posting-Host: 82.245.180.242


Pour l'instant les unixoides ont fait la bascule sizeof(long)==8, le reste
du monde (et il y en a pas mal) ont encore une ABI assez ancrée 32bits.



Windows est le seul OS 64 bits à ma connaissance à utiliser des long sur 32
bits. Les Unix, OpenVMS et z/OS utilisent le modèle LP64.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Antoine Leca
Vincent Lefevre écrivit :
Avoir un type fixé implicite est complètement arbitraire.



Évidemment.

Par exemple, pourquoi int et pas double,
ou le type entier le plus long?



Parce qu'au départ (BCPL), il n'y avait pas de flottants, et encore
moins de long, seulement des entiers.

Pourquoi pas le même type que celui utilisé par le préprocesseur?



Par le quoi ? :-)

Bref, cette notion de type implicite était foireuse dès le départ.



Non.

C est devenu de plus en plus compliqué, et à un moment cette nouvelle
complexité nécessite que des choses qui furent simples et limpides
deviennent des cas particuliers de situations plus complexes ; pour
assurer la transition, le mécanisme des choses implicites est une aide
précieuse dans un premier temps, mais ensuite il faut s'en passer.

Cependant, on ne peut pas jeter le bébé avec l'eau du bain, car le
développement de C (à la même époque que Algol-68) montre bien les
avantages d'un développement progressif (donc avec des raccourcis
implicites pendant certaines périodes) sur une norme monolithique qui
sorte toute armée du casque du comité ad-hoc...


Antoine
Avatar
Samuel DEVULDER
Vincent Belaïche a écrit :
Bonjour,

En toute rigueur en effet quand on parle de nombre binaire,



L'exposant est le nombre après le 'p' dans le contexte du printf %a.

ou de nombre
décimal, on fait référence à ses propriétés mathématiques et non à sa
représentation textuelle,



Heu pour printf %a on parle surtout de la représentation textuelle et de
rien d'autre.

c'est à dire qu'on parle de sa base numération
en mémoire.



Non pas pour la partie qui suit le 'p' dans printf %a. On est pas dans
la représentation mémoire du flottant, ou dans ses propriétés
numériques, mais de son affichage à l'écran pour une être humain. Et
dans l'affichage, ce qui suit le p est un nombre décimal indiquant la
puissance de 2 à appliquer à la partie fractionnaire. C'est exactement
ce qu'il faut comprendre de la description de la norme: [−]0xh.hhhh p±d,
avec pour la partie "d": The exponent always contains at least one
digit, and only as manymore digits as necessary to represent the decimal
exponent of 2.


Autre chose, lorsqu'on parle de nombre à virgule flottante intervient
aussi la base de logarithme utilisée pour l'exposant. Je pense que dans
la référence cité le "binary" dans "binary exponent part" faisait
référence à cela et non au format de représentation en mémoire/en texte
comme la discussion qui vient d'avoir lieu a pu le laissé entendre. On
peut donc résumer l'ensemble comme cela :

| format | %e, %g, %f | %a | en mémoire |
|------------------------------------+------------+----+------------|
| base de numération de l'exposant | 10 | 10 | 2 |
| base de logarithme de l'exposant | 10 | 2 | 2 |
| base de numération du significande | 10 | 16 | 2 |



Oui, encore qu'en interne on peut aussi trouver une base 10 pour la
partie non fractionnaire du flottant (decimal32 par ex).

Fondamentalement la représentation textuelle d'un nombre ne dépend pas
de sa représentation mémoire. Les calculettes scientifiques affichent
les nombres comme un %g le ferait en C, mais pourtant en interne en
mémoire on ne trouve pas forcément un truc basé sur une puissance de 2.
Par exemple il peut y avoir une représentation sous forme d'octets BCD
(1 octet pour l'exposant, et N autres pour la mantisse).

sam.
Avatar
Samuel DEVULDER
Jean-Marc Bourguet a écrit :
Samuel DEVULDER writes:

On attends tous la révision *Vincent* de la norme.



Surprise! les normes ont des défauts. Les plus graves sont corrigés (le
troisième jeu de révision de C99 date de 2007, je doute qu'il y en ai un
autre avant la publication de C1X), quand on s'en rend compte, que ce n'est
pas trop invasif, et qu'on se met d'accord sur la correction. Mon
impression est qu'ici le problème est tellement peu grave que la correction



Tu as raison.. et encore si problème il y a. Tous n'ont pas remarqués de
pbs dans cette partie là de la norme. Je doute même que ca fasse
ambiguïté si on avait pas tellement embrouillé les cartes dans ce fil de
discussion.

en serait laissée à l'éditeur (comme les fautes d'orthographe et les
incohérences de typographie ne créant pas d'ambiguité) et jamais publiée
dans un TC. Ça ne m'étonnerait pas du tout que Vincent ait connaissance de
problèmes techniques plus graves concernant les nombres à virgule
flottante.



Oui comme on dit: il vaut mieux occuper son intelligence à des conneries
que de laisser sa connerie s'occuper des choses intelligentes. ;-)

sam.
Avatar
Samuel DEVULDER
Jean-Marc Bourguet a écrit :
Samuel DEVULDER writes:

Vincent Lefevre a écrit :

Donc contrairement à ce qu'affirme Samuel, ce n'est pas le reste
du monde qui utilise une ABI 32 bits.


Je n'ai pas dit cela. J'ai dit "il n'y a pas que MSVC" qui soit resté avec
sizeof(long)==4. N'inverse pas mes propos STP (déjà que tu inverses la
définition de strtod et printf..)

sam (renversant!)



Qui donc est-ce qui a écrit:

Date: Wed, 07 Apr 2010 09:19:56 +0200
From: Samuel DEVULDER
User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
Message-ID: <4bbc320c$0$22387$
NNTP-Posting-Date: 07 Apr 2010 09:19:42 MEST
NNTP-Posting-Host: 82.245.180.242


Pour l'instant les unixoides ont fait la bascule sizeof(long)==8, le reste
du monde (et il y en a pas mal) ont encore une ABI assez ancrée 32bits.






Non, je faisais référence au msg d'origine en réponse à Antoine :

----8<-----------------------
Antoine Leca a écrit :

Il reste Microsoft qui eux sont restés sur long2 bits, tout en
expliquant qu'il ne faut pas utiliser les types de base (ni printf).





Oh il n'y a pas que MSVC qui a des long à 32bits..
----8<-----------------------

Qui lui même avait écrit:

----8<-----------------------
Antoine Leca a écrit :

> Il reste Microsoft qui eux sont restés sur long2 bits, tout en
> expliquant qu'il ne faut pas utiliser les types de base (ni printf).


----8<-----------------------

Oui donc je re-écris: il n'y a pas que MSVC qui soit encore 32bits. Rien
de plus, rien de moins.

sam.
Avatar
Antoine Leca
Jean-Marc Bourguet écrivit :
Samuel DEVULDER writes:
Vincent Lefevre a écrit :
Utiliser des int implicites, par exemple.


Pourquoi? Parce que C99 l'interdit?



C99 l'interdit, malgré le fait que le problème de compatibilité
sont pris très au sérieux lors de la normalisation,



<APARTÉ>
Et encore, ils se font manifestement fait taper sur les doigts, et les
règles officielles sont apparemment encore plus strictes pour C1X.
</APARTÉ>

parce que c'est quasiment universellement considéré comme une
pratique non recommandable, héritage [...]



Mmm. Certes, mais je crois surtout que la vraie raison, c'est que tu ne
peux pas avoir à la fois les int implicites *et* deux des nouveautés de
C99 que sont les déclarations de variables for locales d'une part, et le
mélange libre des déclarations et des instructions d'autre part.

Et je me souviens que la discussion fut /très/ courte !


Par contre, il est bien possible que le comité dans son ensemble n'a pas
réalisé à ce moment la quantité de code rouillé qui devenait
incompatible, et la quantité de modifications (évidentes pour la
quasi-totalité) que les développeurs devraient faire pour faire passer
ces vieux codes sur des compilateurs C99.

D'un autre côté, je n'ai pas l'impression (mais je manque singulièrement
de pratique) que les compilateurs C99 aient un comportement très
intelligent à ce niveau : il semble que l'attitude courante est de
fournir un mode C90 (avec le parseur qui accepte les int implicites) et
par ailleurs un parseur C99 (qui ne les envisage pas du tout, donc
renvoie des messages parfois abscons); évidemment, il est beaucoup plus
compliqué d'avoir un parseur adaptatif, qui attends du C99 mais qui
laisse passer des int implicites dans certains endroits sans ambiguïté,
comme les déclarations ancien style, ou en présence d'un spécificateur
de stockage qui précèderait (le static a=4; ci-dessus). Et quand le
client se plaint, la réponse pré-écrite est « actualiser votre code » ;
ce qui est le contraire des objectifs de la norme C, qui a toujours dit,
« la base de code est importante, les implémentations ne le sont pas » ;
en gros, les vendeurs de compilateur tiennent le haut du pavé :-(


Antoine
Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
Samuel DEVULDER writes:

On attends tous la révision *Vincent* de la norme.



Surprise! les normes ont des défauts. Les plus graves sont corrigés (le
troisième jeu de révision de C99 date de 2007, je doute qu'il y en ai un
autre avant la publication de C1X), quand on s'en rend compte, que ce n'est
pas trop invasif, et qu'on se met d'accord sur la correction. Mon
impression est qu'ici le problème est tellement peu grave que la correction
en serait laissée à l'éditeur (comme les fautes d'orthographe et les
incohérences de typographie ne créant pas d'ambiguité) et jamais publiée
dans un TC. Ça ne m'étonnerait pas du tout que Vincent ait connaissance de
problèmes techniques plus graves concernant les nombres à virgule
flottante.



De toutes facons, la norme C est en grande partie silencieuse concernant
les flottants. De memoire, elle mentionne surtout qu'une implementation
decente devrait dire si elle utilise aussi IEEE754 ou pas.

Ca n'empeche pas d'etre precis et d'essayer de faire maximalement portable,
mais c'est vraiment un domaine ou il convient de faire tres tres attention
a ce qu'on raconte.

Sam, maintenant qu'a peu pres tout le monde s'est range du cote de Vincent,
tu ne voudrais pas betement laisser tomber et "stop to argue until you're
blue in the face" (desole, je vois pas comment la traduire, celle-la)
Avatar
espie
In article <20100407075358$,
Vincent Lefevre wrote:
Dans l'article <4bbc2c39$0$24223$,
Samuel DEVULDER écrit:

Vincent Lefevre a écrit :
> Dans l'article <4bbb7cce$0$18404$,
> Samuel DEVULDER écrit:
>
>> Ca veut dire quoi "sale" pour toi?
>
> Utiliser des int implicites, par exemple.



Pourquoi? Parce que C99 l'interdit?



Non, parce que ce qui est implicite est souvent sale (mais à voir
au cas par cas).

On te parles justement de regarder ce qui se faisait avant.



Justement, je n'ai pas attendu C99 pour ne *pas* utiliser les types
implicites dans mes programmes!



De toutes facons, ca fait plus de dix ans que gcc emet des avertisssements
pour les types implicites avec -Wall... Il a bien fallu nettoyer au moins
les fichiers d'entetes (ceux de X11 par exemple), ne serait-ce que pour
ne pas etre innonde d'avertissements inutiles a la premiere compile avec
-Wall...