OVH Cloud OVH Cloud

problème de flottant

19 réponses
Avatar
none
Je dois travailler avec des flottants pour tracer l'axe d'un repère.
J'ai une routine qui renvoie un pixel en fonction de coordonnées
flottantes (des double).
Maintenant, je dois dessiner un tiret de, disons -1.0 jusqu'à 1.0 tous
les 0.1, donc -1.0, -0.9, ..., 0.0, ..., 1.0

Apparemment, partir de -1.0 et ajouter 0.1 à chaque pas, ça ne
fonctionne visiblement pas. Pour le tiret du milieu, quand je compare ma
valeur à 0.0, ça me renvoie faux :/ Alors que pourtant, je n'ai fait
qu'incrémenter ma valeur de 0.1.
Je pense que c'est un problème récurrent mais j'ai vraiment du mal à
comprendre.
Comment faire proprement pour avoir -1.0, -0.9, etc .. ?

9 réponses

1 2
Avatar
kanze
Sylvain wrote:
kanze wrote on 20/03/2006 11:41:

2- puisque apparemment ce que tu aimes développer le plus est
l'art de la contradiction (ni systématiquement intéressante,
ni spécialement en charte), je me sens obligé d'indiquer que
ce "bizutage" me laisse de glace.


C'est plutôt que j'aime la correction, et quand on poste des
bêtises, je me sens obligé à les corriger. J'ai une assez faible
tolérance de l'incompétence.

un flottant est nécessairement une valeur définie + ou - sa
précision,


Strictement parlant... Un flottant a une valeur précise ; il
n'y a pas de + ou -. Pour des raisons évidentes
(représentation finie), les flottants ne peuvent pas
représenter tous les réels (ni toutes les rationnelles)


donc "strictement parlant", je te laisserais maintenant
monologuer ce type de platitude.


Quand on veut écrire des programmes correctes, il faut savoir
exactement ce qu'on manipule comme données.

0.1 est une des valeurs qu'ils ne peuvent pas représenter.


et t'as décréter ça tout seul sans même connaître la précision
de son type double !! ben tu vois un Cray tout bête se
représente parfaitement 0.1


Je vois que tu n'as jamais programmé sur un Cray. Il utilise (ou
utilisait) un format binaire. Pas le même que IEEE, évidemment,
mais c'était base 2, quand même.

qui fait qu'il n'ajoute pas 0.1 à chaque passage dans la
boucle, mais quelque chose de proche.


tu expliques ça à qui ???????? 4 personnes l'ont déjà dit.


D'autres l'avaient bien dit. Je ne me suis donc pas senti obligé
à corriger leur postings. Tu suggérais que le problème était du
à des erreurs d'arrondi dans l'addition. Je ne fais que
corriger ton erreur.

Ça dépend des formats, mais en IEEE (le format le plus
répandu aujourd'hui), la valeur décimale de la mantisse
s'étend de 0.5 à 1.0-epsilon (ou epsilon est 2^-53, je
crois).


la valeur absolue de la mantisse est toujours comprise entre 1
et la base de dénombrement (le premier bit étant caché car
toujours prédictible, cette mantisse se ramène en base 10 à
une quasi partie fractionnaire pure (un nombre décimale sans
partie entière)


Je suggère que tu lis l'article que j'ai cité. Et aussi ce que
tu as posté et auquel je répondais, où tu disais que la mantisse
se situe entre 0 et 1. Selon la façon d'interpréter l'exposant,
la mantisse se situe soit dans l'intervale [1/b;1[, soit dans
l'intervale [1;b[. Il ne s'approche jamais à 0.

Le fait que dans certaines représentations, il est possible de
ne pas stocker le bit de poids forts n'entre pas en ligne de
jeux ; quand on travaille au niveau de la représentation
physique, il faut bien en tenir compte.

Il y a aussi des valeurs spéciales, identifiées par une
valeur spéciale dans l'exposant -- 0.0 est sans doute celle
qu'on rencontre la plus souvent.


de l'exposant *et* de la mantisse.


La mantisse entre en compte dans l'évaluation de la valeur
spéciale. Il suffit de régarder l'exposant pour savoir si on a
une valeur spéciale ou non -- pour un double, si l'exposant est
0 ou 1023, on a une valeur spéciale : 0.0, un dénormal, une
infinité ou un NaN.

soit il y a le nombre zero (E = 0; F = 0; S = 1)

tu as juste oublié:
-0 (E = 0; F = 0; S = 1)
-Infinity
Infinity
NaN


Étant donné que je n'ai rien énuméré, je n'ai rien oublié. Dans
la pratique, parmi ces valeurs spéciales, c'est sûrement 0.0
qu'on voit la plus souvent.

Là aussi, ça dépend du point de vue. La valeur du résultat
est bien définie.


on va dire ça; tabl[4325] est "indéfini" mais savoir comment
le dernier bit d'un flottant est arrondi par tous les unités
flottantes de tous les fondeurs est "définie" .. "selon le
point de vue de James".


Selon la norme IEEE. (Mais je n'ai pas l'impression que tu l'as
lu.)

Seulement, dans certains cas, elle sera différente
de celle du résultat de l'opération sur les réels. Mais


c'est quoi "réels", c'est pas dans IEEE 754 ni dans IEEE 854.


C'est dans la mathématiques. Je vois mal un mathématicien (ou un
informaticien) qui ne les connaît pas.

[...]
Ça dépend de l'application ; souvent, les valeurs en entrée
sont déjà des approximations, et c'est tout à fait normal de
prendre en compte des epsilons quand on cherche une valeur
précises -- en fait, ce qu'on veut, au niveau de
l'application, c'est déjà x+/-epsilon (avec un epsilon qui
dépend de l'application).


ça a un rapport avec la question, le fil, la chartre ???
ou c'est juste une envolée de plus ?


Ça a un rapport avec comment on utilise les flottants dans un
programme.

Mais ce n'est pas une règle générale ; ça dépend de
l'application. Et il faut bien ne pas oublier que si on
définit un isEqual() approximatif, alors isEqual(a,b) &&
isEqual(b,c) n'implique plut isEqual(a,c) -- ce qui peut
faire échouer certaines algorithmes.


oui, seulement si tu ne sais pas coder ton isEqual.


Sans connaître ce qu'il doit faire, je ne sais effectivement pas
comment le coder. Et ce qu'il doit faire dépend de
l'application. Si c'est simplement :

bool
isEqual( float a, float b )
{
return a == b ;
}

c'est vrai qu'il est transitif. Mais alors, pourquoi la
fonction ? Et que veut dire « approximatif » ? Dès que tu
commences à faire jou-jou avec des +/- epsilon, il cesse d'être
transitif. Parfois, ça va, mais il faut bien savoir ce qu'on
fait.

Il y a pire, évidemment, et certains algorithmes, pour
certaines valeurs (qui n'apparaîtront pas dans vos tests,
évidemment) peuvent ne pas converger avec les opérations sur
des flottants, alors qu'ils convergeront bien avec les mêmes
opérations sur des réels.


si "réel" voulait signifier "précision arbitraire" (via une
librarie es-spéciale et non une simple unité de calcul
flottant) c'est faux également.


N'importe quel informaticien doit savoir au moins ce que sont
les nombres réels. Je m'étonnerais qu'on puisse avoir un bac S
(ou même un bac L) sans les avoir vus.

concrétement:
ne pas coder if (f == 1.0) {}
mais if (fabs(f - 1.0) < 1e-8) {}


Si tu sais que dans ton application, la précision des
valeurs est de l'ordre 1e-8.


?!?? non, si tu sais que tu utilises des float (32bits), on
utilisera 1e-12 avec des doubles et 1e-14 avec des long
doubles.


Et tu as tiré ces valeurs d'où ? De ton chapeau ? (Et pourquoi
la différence entre double et long double, étant donné qu'ils
ont la même représentation sur des plateformes les plus
courantes ?)

Dans les rares cas où je me sers des flottants, je m'arrange
pour que les valeurs soient toujours exactes.


c'est pas du n'importe quoi là ??, tu as répété après tout le
monde que tous les nombres flottants ne pouvaient pas avoir
une représentation exacte de leur valeur, mais toi,
abracadabra, tu t'"arranges" avec eux et hop "c'est exact";
tiens codes donc exactement 7/5


Je m'arrange à ne pas avoir 7/5. Comme ça, le problème ne se
pose pas.

En revanche, dans une application où je traiterais des
valeurs lues des instruments de mésure électronique, la
précision serait plutôt de l'ordre 1e-2 ou 1e-3 -- les
instruments ne peuvent pas me donner de plus, de toute
façon.


si, si, c'est vraiment du n'importe quoi. (pousse la porte
d'un labo de physique au moins une fois, tu verras c'est
intéressant).


J'ai travaillé longtemps comme ingenieur en électronique. Je
sais que dans les labos de recherche, il existe des instruments
de mesure plus précis. Mais dans l'industrie, c'est rare d'avoir
plus de deux ou trois chiffres décimaux, et encore. Dans
l'électronique, par exemple, les resistances qu'on utilisent
d'habitude ont une précision de 10%.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Sylvain
Arnaud Meurgues wrote on 21/03/2006 09:21:

« un Cray tout bête », c'est déjà une expression étrange.

Par curiosité, quelle genre de représentation binaire des flottants
utilise ce Cray tout bête pour représenter 0.1 de manière exacte ?


désolé c'était un joke, tout le monde sait que certaines familles de
Cray (X-MP) se caractérisent par leur manque de précision.

tout ceci étant hors chartre, google IEEE.


Ce n'est pas plus hors charte que vos réponses dans le fil « pb
iwebbrowser2 ».


je ne saisis pas, à relire la FAQ §1.1.7, le post était convenable.
(l'organisation de la hiérarchie microsoft.public.fr autorisait
également à répondre ici plutôt que de 'faire suivre').

Mais si ça vous amuse de développer l'incohérence en
plus du mépris...


la spec. IEEE reste (un peu, tout de même, ...) hors chartre et l'exposé
de toutes ses finesses n'était pas indispensable; mais peut être est-ce
méprisant que de convier à googler sans un "pour toute information
patati merci de consulter patata ...".

Il dit que 0.0 est celle qu'on rencontre le plus souvent. [...]


j'ai bien lu qu' "il" dit que; toutefois de mon expérience on a aucune
raison de rencontrer plus souvent 0.0 que 1.0 ou 2.37 ... par contre les
débordements (infini ou NaN) sont toujours possibles et sont à traiter
(pour un code à vocation numérique s'entend).

savoir comment le dernier bit d'un flottant est arrondi


Ne pourrait-ce pas être indiqué par numeric_limits<float>::round_style
(tiens, ça c'est en charte) ?


il est facile de rencontrer un compilo ne connaisant pas ces limites là;
par ailleurs la précision d'un même code peut changer selon le proc.
arith. (sur la famille 680x0 par exemple la précision interne d'un
double fait des fois 10 octets, des fois 12 octets).

Comment peut-on coder un isEqual approximatif (différent du =, donc) et
transitif ?


en jouant sur l'erreur relative (intuitée, calculée, ...); si on
considère que des expressions (immédiates ou calculées) sont "justes" à
10^-n près alors on vérifiera:

si (fabs(a - b) < 10^-n) et (fabs(a - c) < 10^-n)
alors (fabs(b - c) < 10^-n)

cette façon de procéder n'est nullement unique et chacun dans un code
concret pourra réfléchir à un traitement plus pertinent; gardant
notamment à l'esprit que l'arithmétique flottante est généralement non
associative.

Je pense qu'ici, réels signifie réels, mathématiquement parlant.


je l'ai bien lu comme ça, mais un CPU ne traite pas de "réels
mathématiques" (Mapple ou Mathematica essaient, un code C++ rarement).

Selon vous, une suite qui converge avec des réels converge
obligatoirement avec des flottants ?


la question manque peut être de précision; dans nombre de cas la réponse
sera positive; 1/x converge vers 0 pour x "math. réel" ou "inform.
flottant" (1/b aussi, d'ailleurs).

imho, converger ne signifie pas atteindre exactement une valeur mais
tendre vers cette valeur.

dans le cas général, on définira, ici aussi, un critère d'arrêt qui
prend en compte la précision du calcul pour déterminer si le calcul a
atteint ou non le résultat voulu (exemple quel est x tel que 1/x == 0 à
10^-6 près).

il existera toujours des expressions à forte divergence qui auront du
mal à converger, elles seront codées de manière particulière ... mais je
ne pense pas que l'on parlait de cela.

Si tu sais que dans ton application, la précision des valeurs
est de l'ordre 1e-8.
?!?? non, si tu sais que tu utilises des float (32bits), on utilisera

1e-12 avec des doubles et 1e-14 avec des long doubles.


Et avec des floats ?


j'avais déjà donné la valeur 1e^-8 ... je peux répéter que dans un vrai
code une erreur relative fixée a priori peut ne pas convenir, la valeur
pertinente doit tenir compte de la précision de chaque opération (cumul
des erreurs relatives sur chaque opération) et de la "magnitude" des
nombres (si par exemple des nombres dénormaux interviennent durant les
étapes du calcul, la précision du résultat est grandement réduite).

Dans les rares cas où je me sers des flottants, je m'arrange pour que
les valeurs soient toujours
exactes.



Je suppose qu'il ne vous est pas venu à l'esprit qu'il pouvait
s'arranger pour n'avoir à utilier que des nombres représentables.


nuance, il ne m'est pas venu à l'esprit que cela puisse être appliqué!

s'il s'agit d'un programme réalisant des acquisitions, il reçoit des
nombres qui ont déjà été ramené au plus proche flottant représentable,
il ne peut d'aucune façon s'il doit refuser une entrée qui ne serait pas
représentable.

s'il reçoit des nombres par saisie, doit-on parser le nombre littéral
(son écriture texte) avant de daigner l'accepter ou non ?

s'il s'agit d'un résultat intermédiaire, doit-on évaluer les opérandes
(et si oui selon quelles règles) pour continuer ou non le calcul ?

si le point ne se limite qu'à une vigilance portée sur la factorisation
de constantes (dans une expression complexe) afin que celles-ci soient
représentables (ou représentables avec la plus faible erreur possible),
je crains que cela ne joue que dans d'infimes cas particuliers (même la
graduation d'un axe utilise généralement des bornes définies par
l'utilisateur ou contraintes par la fonction).

Sylvain.



Avatar
Arnaud Meurgues
Sylvain wrote:

« un Cray tout bête », c'est déjà une expression étrange.
Par curiosité, quelle genre de représentation binaire des flottants
utilise ce Cray tout bête pour représenter 0.1 de manière exacte ?
désolé c'était un joke, tout le monde sait que certaines familles de

Cray (X-MP) se caractérisent par leur manque de précision.


C'était une plaisanterie ?! En gros, dans la même phrase, vous traitez
James de crétin et plaisantez sur l'imprécision « connue » des Cray :

«
0.1 est une des valeurs qu'ils ne peuvent pas représenter.


et t'as décréter ça tout seul sans même connaître la précision de son
type double !! ben tu vois un Cray tout bête se représente
parfaitement 0.1
»


Mais bon, vous allez tout de même nous expliquer avec quelle précision
du type double 0.1 est représentable, non ? « Blague » à part...

tout ceci étant hors chartre, google IEEE.
Ce n'est pas plus hors charte que vos réponses dans le fil « pb

iwebbrowser2 ».
je ne saisis pas, à relire la FAQ §1.1.7, le post était convenable.



Sauf si vous avez lu 1.1.2 avant.

(l'organisation de la hiérarchie microsoft.public.fr autorisait
également à répondre ici plutôt que de 'faire suivre').


Je ne vois pas en quoi l'organisation de la hiérarchie microsoft
autorise quoi que ce soit sur la hiérarchie fr.

la spec. IEEE reste (un peu, tout de même, ...) hors chartre et
l'exposé de toutes ses finesses n'était pas indispensable;


Sauf que le code :

double a = 0.1;
double b = 1.0;
while (b != 0.0) b -= a;

est purement C++ et nécessite de comprendre comment fonctionnent les
flottants pour comprendre pourquoi il a très peu de chance de
fonctionner comme on s'y attend.

mais peut
être est-ce méprisant que de convier à googler sans un "pour toute
information patati merci de consulter patata ...".


Il est méprisant, lorsqu'on arrive sur un groupe, de rappeler la charte
a des personnes qui y interviennent depuis plusieurs années (voire qui
ont participé à l'élaboration de la charte), surtout lorsqu'on le fait à
tort.
Mais c'était le ton général du message qui était imprégné de mépris et
d'agressivité :
« puisque apparemment ce que tu aimes développer le plus est l'art de la
contradiction (ni systématiquement intéressante, ni spécialement en
charte), je me sens obligé d'indiquer que ce "bizutage" me laisse de
glace. »
« donc "strictement parlant", je te laisserais maintenant monologuer ce
type de platitude. »
« et t'as décréter ça tout seul sans même connaître la précision de son
type double !! ben tu vois un Cray tout bête se représente parfaitement
0.1 »
« tu expliques ça à qui ???????? 4 personnes l'ont déjà dit. »
etc.

Il dit que 0.0 est celle qu'on rencontre le plus souvent. [...]
j'ai bien lu qu' "il" dit que; toutefois de mon expérience on a

aucune raison de rencontrer plus souvent 0.0 que 1.0 ou 2.37 ...


Comme quoi vous semblez ne pas avoir la même expérience. À propos,
depuis combien de temps travaillez-vous dans l'informatique (ça va
permettre de mesurer la longueur des expériences de chacun) ?

Ne pourrait-ce pas être indiqué par
numeric_limits<float>::round_style (tiens, ça c'est en charte) ?
il est facile de rencontrer un compilo ne connaisant pas ces limites

là; par ailleurs la précision d'un même code peut changer selon le
proc. arith. (sur la famille 680x0 par exemple la précision interne
d'un double fait des fois 10 octets, des fois 12 octets).


Ce qui est connu au moment de la compilation. Mais bon, la précision et
la méthode d'arrondi, ça n'est pas la même chose.

Comment peut-on coder un isEqual approximatif (différent du =,
donc) et transitif ?
en jouant sur l'erreur relative (intuitée, calculée, ...); si on

considère que des expressions (immédiates ou calculées) sont "justes"
à 10^-n près alors on vérifiera:

si (fabs(a - b) < 10^-n) et (fabs(a - c) < 10^-n) alors (fabs(b - c)
< 10^-n)


Peut-être, mais ce n'est pas de ça dont on parlait. On parlait de
transitivité (f(a,b) ^ f(b,c) => f(a,c)).

Accessoirement, il me semble que si l'on prend n = 1, a = 0.0, b = 0.09
et c = -0.09, on a :

fabs(a - b) = fabs(0.0 - 0.09) = fabs(-0.01) = 0.09 < 10^-1
fabs(a - c) = fabs(0.0 + 0.09) = fabs(+0.09) = 0.09 < 10^-1

mais

fabs(b - c) = fabs(0.09 + 0.09) = fabs(0.18) = 0.18 > 10^-1

Donc, je réitère ma question. Comment faut-il coder le isEqual pour
qu'il soit approximatif et transitif ?

cette façon de procéder n'est nullement unique et chacun dans un code
concret pourra réfléchir à un traitement plus pertinent;


Heureusement que vous nous laissez cette possibilité.

Je pense qu'ici, réels signifie réels, mathématiquement parlant.
je l'ai bien lu comme ça, mais un CPU ne traite pas de "réels

mathématiques" (Mapple ou Mathematica essaient, un code C++
rarement).


Effectivement. Mais qui vous a parlé de CPU ?

Il disait qu'une suite convergente avec des réels (dans le monde
mathématique) peut ne pas converger avec des flottants (dans le monde
informatique).

Selon vous, une suite qui converge avec des réels converge
obligatoirement avec des flottants ?
la question manque peut être de précision;



Je ne crois pas.

dans nombre de cas la
réponse sera positive;


À cause du « obligatoirement », il suffit d'un cas contraire pour que la
réponse ne puisse pas être positive.

1/x converge vers 0 pour x "math. réel" ou
"inform. flottant" (1/b aussi, d'ailleurs).


Super. Mais ce n'était pas la question.

imho, converger ne signifie pas atteindre exactement une valeur mais
tendre vers cette valeur.


Certes. Converger vers une valeur v, c'est assurer que quelque soit un
delta donné, il existe un rang n de la suite tel que n'importe quelle
valeur de la suite après ce rang n à une différence à la valeur v
inférieure à delta.

dans le cas général, on définira, ici aussi, un critère d'arrêt qui
prend en compte la précision du calcul pour déterminer si le calcul a
atteint ou non le résultat voulu (exemple quel est x tel que 1/x = > 0 à 10^-6 près).


Oui. Mais ce n'est pas ce dont James parlait.

il existera toujours des expressions à forte divergence qui auront du
mal à converger, elles seront codées de manière particulière ...
mais je ne pense pas que l'on parlait de cela.


C'est quoi, « avoir du mal à converger » ?
Je crois que ce dont parlait James, c'est de suites qui convergent dans
les réels, mais pas dans les flottants, avec les mêmes opérations.

Dans les rares cas où je me sers des flottants, je m'arrange
pour que les valeurs soient toujours exactes.
Je suppose qu'il ne vous est pas venu à l'esprit qu'il pouvait


s'arranger pour n'avoir à utilier que des nombres représentables.
nuance, il ne m'est pas venu à l'esprit que cela puisse être

appliqué!


Sans doute à cause du mépris pour vos interlocuteurs. Vous en déduisez
que ce qu'ils disent ne méritent pas qu'on le croit.

--
Arnaud




Avatar
kanze
Sylvain wrote:
Arnaud Meurgues wrote on 21/03/2006 09:21:


[...]
tout ceci étant hors chartre, google IEEE.


Ce n'est pas plus hors charte que vos réponses dans le fil « pb
iwebbrowser2 ».



Pour être honnête, ce n'est pas que ses réponses qui sont hors
chartre, c'est le fil entier.

Personnellement, ça ne me gène pas plus que ça, dans la mesure
où on n'est pas inondé par de tels fils. Actuellement, ce n'est
pas le cas (même si ça a menacé dans la passée).

Pour être même plus honnête, ce n'est pas plus hors chartre que
le fil sur les threads sous Posix, où je participe fortement
aussi. Alors, je ne jetterai pas de pierre.

je ne saisis pas, à relire la FAQ §1.1.7, le post était
convenable. (l'organisation de la hiérarchie
microsoft.public.fr autorisait également à répondre ici plutôt
que de 'faire suivre').


C'était du spécifique Microsoft, donc hors charte. IEEE se
trouve dans beaucoup d'implémentations différentes de C++ ; la
norme en parle. norme. Ce n'est donc pas hors charte (au moins,
pas complètement).

Comment fonctionne les virgules flottants en C++ n'est
certainement pas hors chartre ; se servir de IEEE à titre
d'exemple est un bon moyen pédégogique pour le faire.

Mais si ça vous amuse de développer l'incohérence en plus du
mépris...


la spec. IEEE reste (un peu, tout de même, ...) hors chartre
et l'exposé de toutes ses finesses n'était pas indispensable;


C'est toi qui a commencé. Et connaître les subtilités des
virgules flottants est indispensable si tu veux écrire du code
qui marche.

mais peut être est-ce méprisant que de convier à googler sans
un "pour toute information patati merci de consulter patata
...".


Pas du tout. Il y a beaucoup de choses où la réponse dépasse les
bornes de ce qu'on peut raisonablement mettre dans un posting.
"What Every Computer Scientist Should Know about Floating Point
Arithmetic" fait plus de cents pages, et il ne couvre qu'un
minimum.

Il dit que 0.0 est celle qu'on rencontre le plus souvent. [...]


j'ai bien lu qu' "il" dit que; toutefois de mon expérience on
a aucune raison de rencontrer plus souvent 0.0 que 1.0 ou 2.37


Il a dit que 0.0 est la valeur spéciale qu'on rencontre le plus
souvent. 1.0 ou 2.37 ne sont pas des valeurs spécales.

... par contre les débordements (infini ou NaN) sont toujours
possibles et sont à traiter (pour un code à vocation numérique
s'entend).


Certainement.

savoir comment le dernier bit d'un flottant est arrondi


Ne pourrait-ce pas être indiqué par
numeric_limits<float>::round_style (tiens, ça c'est en
charte) ?


il est facile de rencontrer un compilo ne connaisant pas ces
limites là;


De moins en moins facile, quand même. Mais c'est vrai qu'on ne
peut pas toujours utiliser la dernière version du compilateur.

par ailleurs la précision d'un même code peut changer selon le
proc. arith. (sur la famille 680x0 par exemple la précision
interne d'un double fait des fois 10 octets, des fois 12
octets).


La précision peut même changer selon le niveau d'optimization --
sur Intel, les calculs dans le processeur flottant se font
toujours en long double. Les valeurs intermédiaires qui restent
dans un règistre flottant retient cette précision
supplémentaire, celle que le compilateur sauve en mémoire non.

C'est un phénomène très frustrant pour celui qui essaie
d'analyser la stabilité d'un algorithme.

Comment peut-on coder un isEqual approximatif (différent du
=, donc) et transitif ?


en jouant sur l'erreur relative (intuitée, calculée, ...); si
on considère que des expressions (immédiates ou calculées)
sont "justes" à 10^-n près alors on vérifiera:

si (fabs(a - b) < 10^-n) et (fabs(a - c) < 10^-n)
alors (fabs(b - c) < 10^-n)

cette façon de procéder n'est nullement unique et chacun dans
un code concret pourra réfléchir à un traitement plus
pertinent; gardant notamment à l'esprit que l'arithmétique
flottante est généralement non associative.


Et qu'une telle définition de l'« égalité » n'est pas
transative. Et qu'il n'a du sens que pour un sous-ensemble très
limité de valeurs, et que pour certaines applications seulement.

Dans les rares cas où je me sers des flottants, je
m'arrange pour que les valeurs soient toujours exactes.



Je suppose qu'il ne vous est pas venu à l'esprit qu'il
pouvait s'arranger pour n'avoir à utilier que des nombres
représentables.


nuance, il ne m'est pas venu à l'esprit que cela puisse être
appliqué!


Et cependant, c'est assez fréquent, au moins dans certains
domaines. On sait, par exemple, qu'un double (IEEE, en tout cas)
peut représenter tous les entiers de -2^53 à 2^53 de façon
exacte. Sur une machine 32 bits, c'est mieux qu'un long.
Évidemment, il faut appliquer des corrections à la suite d'une
division, à l'aide de modf, mais on s'en servait souvent dans
les implémentations des valeurs monétaires, par exemple ;
9007199254740992 centîmes étant une limite acceptable,
2147483648 non.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
Sylvain
Arnaud Meurgues wrote on 23/03/2006 08:59:

vous traitez James de crétin et plaisantez sur l'imprécision


vous êtes seul responsable de ces propos là; ce n'est pas mon langage.

« connue » des Cray :


pour qui les a pratiqué, à tout le moins.

Mais bon, vous allez tout de même nous expliquer avec quelle précision
du type double 0.1 est représentable, non ? « Blague » à part...


qui reproche de troller ????

blague à part j'ai déjà répondu - il me semblait évident
"mathématiquement" que 1/16 + 1/32 + 1/256 + ... ne pouvait que
converger vers 0.1 mais pas l'atteindre; c'est bizarre j'utilise vos
mots et sans doute encore vous vous enflammerez ...

tout ceci étant hors chartre, google IEEE.
Ce n'est pas plus hors charte que vos réponses dans le fil « pb

iwebbrowser2 ».
je ne saisis pas, à relire la FAQ §1.1.7, le post était convenable.



Sauf si vous avez lu 1.1.2 avant.


rassures-toi j'avais lu le 1.1.2 aussi, et puis le §2, le §3, le §7
(non, y'a pas de 4, 5 ni 6) bref (autre troll passionnant).

ce qui est intéressant dans ta remarque, c'est que:
1- fr.comp.ms-windows.programmation n'existe plus
2- microsoft.public.fr.vc est très orienté fonctionnement (bug) de l'IDE
de VC mais très peu programmation C++ en utilisant VC; la question était
un blocage d'un code (pas de l'outil utilisé) et ne pouvait que trouver
plus de réponse ici que là-bas.

Je ne vois pas en quoi l'organisation de la hiérarchie microsoft
autorise quoi que ce soit sur la hiérarchie fr.


cf ci-avant.

Sauf que le code :
double a = 0.1;
double b = 1.0;
while (b != 0.0) b -= a;
est purement C++


oh ça se compile aussi en C K&R...

et nécessite de comprendre comment fonctionnent les
flottants pour comprendre pourquoi il a très peu de
chance de fonctionner comme on s'y attend.


je suis d'accord, il me semble même que mon post disait cela.

ce que je ne m'explique pas c'est l'envie manifestée / l'ardeur déployé
/ etc à m'expliquer que je dis "des bétises" qui a une légère paraphrase
près sont exactement les arguments que l'on m'oppose (j'entends, si l'on
considère que la rhétorique acceptable ici est celle d'un développeur
normal pas forcément celle d'un agrégé es-lettres).

Il est méprisant, lorsqu'on arrive sur un groupe, de rappeler la charte
a des personnes qui y interviennent depuis plusieurs années (voire qui
ont participé à l'élaboration de la charte), surtout lorsqu'on le fait à
tort. [...]


il est un peu irritant, lorsque l'on arrive sur un groupe, de se faire
bouler par des "c'est par professionnel", "je voudrais pas de ça chez
moi", "c'est des bétises", etc, etc ...

disons 1 partout, et tournons cette page (btw, professionellement c'est
mieux comme ça, j'ai déjà plus que suffisant et je ne suis pas voulu ici
"me l'a péter" pour trouver un quelconque emploi).

Comme quoi vous semblez ne pas avoir la même expérience. À propos,
depuis combien de temps travaillez-vous dans l'informatique (ça va
permettre de mesurer la longueur des expériences de chacun) ?


papier svp ! ok, ok, je n'avais pas lu cette clause dans la chartre.
me demander mes références (articles, participation aux comités) eut été
naturel si je vous proposais une révision / un amendement notable (à une
norme, une pratique, ...) pour simplement poster un conseil que tout le
monde oubliera dans une semaine, c'est plus surprenant.

je fais du développement en C/C++ depuis plus de 15 ans (je note "C/C++"
parce que à cette époque le "C++" était loin d'être normalisé). si vous
avez besoin de me mesurer autre chose, y'a qu'a demander.

Ce qui est connu au moment de la compilation.


euh non, justement, j'ai bien écrit "un même code" (pas source).

Mais bon, la précision et
la méthode d'arrondi, ça n'est pas la même chose.


hein ? le fait que certains calculs ne subissent pas les mêmes arrondis
n'influe pas la précision ?? ben il me semble pourtant.

Peut-être, mais ce n'est pas de ça dont on parlait. On parlait de
transitivité (f(a,b) ^ f(b,c) => f(a,c)).
Donc, je réitère ma question. Comment faut-il coder le isEqual pour
qu'il soit approximatif et transitif ?


la transitivité implique un cumul de perte de précision car elle
n'implique pas 1 opération (comparaison) mais 2; dans votre exemple la
relation est vérifiée en considérant que les nombres sont connus à 0.2
près; j'ai dit dans mon premier post qu'un nombre flottant devait être
vu comme "+ ou - sa précision", j'ai reçu mon bois vert, donc je vous
laisse comprendre pourquoi cet intervalle doit être doublé.

[snip]


[snip]

Sylvain.




Avatar
kanze
Sylvain wrote:
Arnaud Meurgues wrote on 23/03/2006 08:59:


[S'agissant des flottants sur un Cray...]
Mais bon, vous allez tout de même nous expliquer avec quelle
précision du type double 0.1 est représentable, non ? «
Blague » à part...


qui reproche de troller ????

blague à part j'ai déjà répondu - il me semblait évident
"mathématiquement" que 1/16 + 1/32 + 1/256 + ... ne pouvait que
converger vers 0.1 mais pas l'atteindre; c'est bizarre j'utilise vos
mots et sans doute encore vous vous enflammerez ...


Je crois qu'il réagissait à ton énoncé : « ben tu vois un Cray
tout bête se représente parfaitement 0.1 » J'avoue qu'il m'a
étonné aussi, parce qu'autant que je sache, le Cray utilise
aussi une représentation binaire. Et comme tu dis ci-dessus, la
somme d'une série finie des 1/2^n ne peut jamais représenter 0.1
parfaitement. Alors sa question.

Évidemment, si on travaille en base 10, comme certains
processeurs dont je me suis servi (il y a très longtemps, quand
même), ou dans certains langages (ou le BCD est de mise) 0.1 ne
pose pas de problèmes. Mais autant que je sache, ce n'est pas le
cas des Cray. (Autant que je sache, ce n'est le cas d'aucune
implémentation C++. Je crois que les flottant base 10 ont
disparu bien avant l'aparition de C++. Mais je peux bien me
tromper ; il y a beaucoup de machines que je ne connais pas.)

[...]

et nécessite de comprendre comment fonctionnent les
flottants pour comprendre pourquoi il a très peu de
chance de fonctionner comme on s'y attend.


je suis d'accord, il me semble même que mon post disait cela.


Tout à fait. En fait, notre désaccorde dans ce fil se limite à
ce que ça veut dire, « comprendre comment fonctionnent les
flottants ». Au moins au départ.

ce que je ne m'explique pas c'est l'envie manifestée /
l'ardeur déployé / etc à m'expliquer que je dis "des bétises"
qui a une légère paraphrase près sont exactement les arguments
que l'on m'oppose (j'entends, si l'on considère que la
rhétorique acceptable ici est celle d'un développeur normal
pas forcément celle d'un agrégé es-lettres).


Il y avait deux choses avec lesquelles je ne suis pas d'accord
dans tes commentaires initiaux. D'abord, tu disais que « un
flottant est nécessairement une valeur définie + ou - sa
précision. » C'est une erreur très répandue, malheureusement,
mais ça reste une erreur. Un flottant a une valeur précise ; ce
n'est ni + ni - quoique ce soit. Ce qui est vrai, c'est qu'un
flottant ne peut pas avoir n'importe quelle valeur réele, et
qu'il arrive que la valeur qu'il a n'est pas la valeur exacte
qu'on voudrait. Mais elle reste une valeur exacte.

L'autre chose, c'est quand tu as écris :

ne pas coder if (f == 0.0) {}
mais if (fabs(f - 1.0) < 1e-8) {}

Ça dépend beaucoup de l'application -- dans la plupart de mes
utilisations de flottant, f == 0.0 est la forme correcte, dans
d'autres, c'est avec 1e-3 qu'il faut comparer, et dans d'autres,
que sais-je.

L'importance, ici, c'est qu'il n'y a pas de solution simple et
unique. L'importance, c'est qu'il faut comprendre ce que sont
les flottants, et coder en fonction de tes propres besoins, dans
ta propre algorithme. Le problème, ce n'est pas ta solution per
se ; le problème, c'est que tu essaies de donner une solution
unique et simple à un problème qui n'en a pas. Et que quelqu'un
risque de te lire, et d'appliquer ta solution sans comprendre le
problème.

Il est méprisant, lorsqu'on arrive sur un groupe, de
rappeler la charte a des personnes qui y interviennent
depuis plusieurs années (voire qui ont participé à
l'élaboration de la charte), surtout lorsqu'on le fait à
tort. [...]


il est un peu irritant, lorsque l'on arrive sur un groupe, de
se faire bouler par des "c'est par professionnel", "je
voudrais pas de ça chez moi", "c'est des bétises", etc, etc
...


Ce n'est pas das ce fil que c'est passé. Et je reste d'avis que
quelqu'un qui écrit x << 1 pour multiplier par 2 n'est pas
professionnel.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Pierre Maurette
[...]
mais ça reste une erreur. Un flottant a une valeur précise ; ce
n'est ni + ni - quoique ce soit. Ce qui est vrai, c'est qu'un
flottant ne peut pas avoir n'importe quelle valeur réele, et
qu'il arrive que la valeur qu'il a n'est pas la valeur exacte
qu'on voudrait. Mais elle reste une valeur exacte.
Les flottants informatiques, pour prendre un exemple des 64 bits

IEEE754 sur 64 bits, sont une tout petite série de quelques rationnels.
Je sais que tout le monde le sait, c'est simplement pour donner le
résultat d'un petit pifométrage: entre 1 et "l'infini", de l'ordre de
1.7e308, la différence moyenne entre deux valeurs successives est de
1e290.
Ce qui est très étonnant, c'est que judicieusement utilisés, ces
trucs-là trouvent le moyen d'être efficaces.
Bin entendu, "judicieusement utilisés" signifie la plupart du temps
"pas utilisés".

--
Pierre Maurette

Avatar
Fabien LE LEZ
On Fri, 24 Mar 2006 16:20:04 +0100, Pierre Maurette
:

Ce qui est très étonnant, c'est que judicieusement utilisés, ces
trucs-là trouvent le moyen d'être efficaces.
Bin entendu, "judicieusement utilisés" signifie la plupart du temps
"pas utilisés".


Pour résumer, les flottants sont efficaces tant qu'on ne les utilise
pas.

Avatar
kanze.james
Fabien LE LEZ wrote:
On Fri, 24 Mar 2006 16:20:04 +0100, Pierre Maurette
:

Ce qui est très étonnant, c'est que judicieusement utilisés,
ces trucs-là trouvent le moyen d'être efficaces. Bin
entendu, "judicieusement utilisés" signifie la plupart du
temps "pas utilisés".


Pour résumer, les flottants sont efficaces tant qu'on ne les
utilise pas.


Les flottants peuvent être efficaces dans la mesure qu'on sait
ce qu'on fait, et qu'on connaît ses limites. C-à-d pour beaucoup
de monde (moi-même compris, sauf pour des cas très restreints),
effectivement, qu'on ne les utilise pas.

L'importance, ici, c'est de connaître ses limites, et ne pas
chercher à les dépasser au moyen des règles arbitraires et non
forcément valides pour ce qu'on veut faire.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


1 2