Je ne parlais pas de la troncation en entier, mais de l'erreur de représentation dès que la valeur est mise dans le double (17.58 dans un double sera-t-il nécessairement plus petit que 17.58, par exemple 17.5799999999999875 ou pourrait-il être plus grand, par exemple pourrait-il devenir 17.5800000000000125.)
Je ne comprends pas ce que tu veux dire. La valeur 17.58 ne serait jamais mis dans un double.
« Mis » était pris dans le sens général d'une affectation ou lecture. Quelque part, quelqu'un pense que c'est 17.58...
double x= 17.58; ou cin >> x; // Et l'utilisateur tape 17.58
C-à-d une conversion de texte en double. Là, autant que je me souviens, la norme ne donne absolument aucune garantie, ni quant à la mode d'arrondie, ni même quant à la précision.
La norme C++, s'entend, parce que IEEE donne quelques garanties pour une implémentation qui se dit conforme IEEE.
[...]
si le type cible est flottant, la direction de l'arrondie dépend de l'implémentation
C'est exactement à quoi je pensais et ce dont je parlais. La valeur finale, vraiment stockée, peut être plus grande.
Mais de quoi ? Quand tu affectes à un double, sur des machines typiques 32 bits, il n'y a potentiellement arrondie ou troncation que si la source est un long double ou un long long. Dans le cas de 17,58, seulement si la source est un long double, d'ailleur (et encore, la valeur exacte n'est pas 17,58) ; si la source est un long long, la valeur est soit 17 soit 18, et dans les deux cas, on peut la représenter de façon exacte sur un double.
Et ceci complique beaucoup toute tentative de « récupération » de la valeur qu'on peut penser avoir stockée.
Je crois, justement, que le problème se situe en aval. À la valeur qu'on peut penser avoir stockée.
[...]
Alors, quelle est ta question exactement ?
Au départ, j'avais mal lu le contexte du message auquel j'ai répondu :-(
Je voulais seulement dire qu'il ne suffit pas d'ajouter .5 après avoir multiplié par une puissance de 10 pour récupérer une valeur qu'on pense avoir stockée, avec une certaine précision (en entier ou autre). Mais le message original parlait de récupérer seulement deux décimales, ce qui est possible bien entendu (mais il n'est pas nécessaire d'utiliser 0.5 alors... voir les autres messages).
C'était un peu ce qui était derrière mon avertissement aussi. Si on multiplie une valeur à deux décimales par 0,196, puis on arrondie à deux décimales avec le méthode proposé, le résultat ne serait pas forcément identique si les opérations se font en binaire que s'ils se font en décimale. Pour commencer, parce que la valeur initiale ne serait pas forcément la même que la valeur décimale, et ensuite parce qu'avec un double binaire, genre IEEE, tu ne vas pas multiplier par 0,196, mais par quelque chose de près. Seulement, les problèmes, ce ne sont pas les questions d'arrondie des doubles. Le vrai problème, c'est qu'on commence avec les valeurs fausses au départ.
-- James Kanze home: www.gabi-soft.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Michel Michaud wrote:
Dans le message 423c5679$0$28004$626a14ce@news.free.fr,
Je ne parlais pas de la troncation en entier, mais de
l'erreur de représentation dès que la valeur est mise dans
le double (17.58 dans un double sera-t-il nécessairement
plus petit que 17.58, par exemple 17.5799999999999875 ou
pourrait-il être plus grand, par exemple pourrait-il devenir
17.5800000000000125.)
Je ne comprends pas ce que tu veux dire. La valeur 17.58 ne
serait jamais mis dans un double.
« Mis » était pris dans le sens général d'une affectation ou
lecture. Quelque part, quelqu'un pense que c'est 17.58...
double x= 17.58;
ou
cin >> x; // Et l'utilisateur tape 17.58
C-à-d une conversion de texte en double. Là, autant que je me
souviens, la norme ne donne absolument aucune garantie, ni quant
à la mode d'arrondie, ni même quant à la précision.
La norme C++, s'entend, parce que IEEE donne quelques garanties
pour une implémentation qui se dit conforme IEEE.
[...]
si le type cible est flottant, la direction de l'arrondie
dépend de l'implémentation
C'est exactement à quoi je pensais et ce dont je parlais. La
valeur finale, vraiment stockée, peut être plus grande.
Mais de quoi ? Quand tu affectes à un double, sur des machines
typiques 32 bits, il n'y a potentiellement arrondie ou
troncation que si la source est un long double ou un long long.
Dans le cas de 17,58, seulement si la source est un long double,
d'ailleur (et encore, la valeur exacte n'est pas 17,58) ; si la
source est un long long, la valeur est soit 17 soit 18, et dans
les deux cas, on peut la représenter de façon exacte sur un
double.
Et ceci complique beaucoup toute tentative de « récupération »
de la valeur qu'on peut penser avoir stockée.
Je crois, justement, que le problème se situe en aval. À la
valeur qu'on peut penser avoir stockée.
[...]
Alors, quelle est ta question exactement ?
Au départ, j'avais mal lu le contexte du message auquel j'ai
répondu :-(
Je voulais seulement dire qu'il ne suffit pas d'ajouter .5
après avoir multiplié par une puissance de 10 pour récupérer
une valeur qu'on pense avoir stockée, avec une certaine
précision (en entier ou autre). Mais le message original
parlait de récupérer seulement deux décimales, ce qui est
possible bien entendu (mais il n'est pas nécessaire d'utiliser
0.5 alors... voir les autres messages).
C'était un peu ce qui était derrière mon avertissement aussi. Si
on multiplie une valeur à deux décimales par 0,196, puis on
arrondie à deux décimales avec le méthode proposé, le résultat
ne serait pas forcément identique si les opérations se font en
binaire que s'ils se font en décimale. Pour commencer, parce que
la valeur initiale ne serait pas forcément la même que la valeur
décimale, et ensuite parce qu'avec un double binaire, genre
IEEE, tu ne vas pas multiplier par 0,196, mais par quelque chose
de près. Seulement, les problèmes, ce ne sont pas les questions
d'arrondie des doubles. Le vrai problème, c'est qu'on commence
avec les valeurs fausses au départ.
--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Je ne parlais pas de la troncation en entier, mais de l'erreur de représentation dès que la valeur est mise dans le double (17.58 dans un double sera-t-il nécessairement plus petit que 17.58, par exemple 17.5799999999999875 ou pourrait-il être plus grand, par exemple pourrait-il devenir 17.5800000000000125.)
Je ne comprends pas ce que tu veux dire. La valeur 17.58 ne serait jamais mis dans un double.
« Mis » était pris dans le sens général d'une affectation ou lecture. Quelque part, quelqu'un pense que c'est 17.58...
double x= 17.58; ou cin >> x; // Et l'utilisateur tape 17.58
C-à-d une conversion de texte en double. Là, autant que je me souviens, la norme ne donne absolument aucune garantie, ni quant à la mode d'arrondie, ni même quant à la précision.
La norme C++, s'entend, parce que IEEE donne quelques garanties pour une implémentation qui se dit conforme IEEE.
[...]
si le type cible est flottant, la direction de l'arrondie dépend de l'implémentation
C'est exactement à quoi je pensais et ce dont je parlais. La valeur finale, vraiment stockée, peut être plus grande.
Mais de quoi ? Quand tu affectes à un double, sur des machines typiques 32 bits, il n'y a potentiellement arrondie ou troncation que si la source est un long double ou un long long. Dans le cas de 17,58, seulement si la source est un long double, d'ailleur (et encore, la valeur exacte n'est pas 17,58) ; si la source est un long long, la valeur est soit 17 soit 18, et dans les deux cas, on peut la représenter de façon exacte sur un double.
Et ceci complique beaucoup toute tentative de « récupération » de la valeur qu'on peut penser avoir stockée.
Je crois, justement, que le problème se situe en aval. À la valeur qu'on peut penser avoir stockée.
[...]
Alors, quelle est ta question exactement ?
Au départ, j'avais mal lu le contexte du message auquel j'ai répondu :-(
Je voulais seulement dire qu'il ne suffit pas d'ajouter .5 après avoir multiplié par une puissance de 10 pour récupérer une valeur qu'on pense avoir stockée, avec une certaine précision (en entier ou autre). Mais le message original parlait de récupérer seulement deux décimales, ce qui est possible bien entendu (mais il n'est pas nécessaire d'utiliser 0.5 alors... voir les autres messages).
C'était un peu ce qui était derrière mon avertissement aussi. Si on multiplie une valeur à deux décimales par 0,196, puis on arrondie à deux décimales avec le méthode proposé, le résultat ne serait pas forcément identique si les opérations se font en binaire que s'ils se font en décimale. Pour commencer, parce que la valeur initiale ne serait pas forcément la même que la valeur décimale, et ensuite parce qu'avec un double binaire, genre IEEE, tu ne vas pas multiplier par 0,196, mais par quelque chose de près. Seulement, les problèmes, ce ne sont pas les questions d'arrondie des doubles. Le vrai problème, c'est qu'on commence avec les valeurs fausses au départ.
-- James Kanze home: www.gabi-soft.fr Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Michel Michaud
Dans le message 423cdc08$0$31892$,
Je ne suis pas sur que tu aies compris le principe de la solution : Pour récuperer un nombre avec n décimales, on fait (int) ((x*10^n)+0.5) (où 10^n est 10 à la puissance n, pas 10 xor n), et pour que ca marche, il faut et il suffit que x soit connu à 0.5*10^-n près.
Je comprends très bien, mais le sens de l'arrondi n'étant pas défini par C++, j'apportais une nuance (inutile dans le contexte du problème spécifique).
Le message original parlait effectivement de récuperer seulement deux décimales, mais la technique est applicable avec n'importe quel nombre de décimales.
Il y a certaines limites quand même :-)
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Dans le message 423cdc08$0$31892$636a15ce@news.free.fr,
Je ne suis pas sur que tu aies compris le principe de la solution :
Pour récuperer un nombre avec n décimales, on fait (int)
((x*10^n)+0.5) (où 10^n est 10 à la puissance n, pas 10 xor n), et
pour que ca marche, il faut et il suffit que x soit connu à
0.5*10^-n près.
Je comprends très bien, mais le sens de l'arrondi n'étant pas défini
par C++, j'apportais une nuance (inutile dans le contexte du problème
spécifique).
Le message original parlait effectivement de récuperer seulement
deux décimales, mais la technique est applicable avec n'importe
quel nombre de décimales.
Il y a certaines limites quand même :-)
--
Michel Michaud mm@gdzid.com
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Je ne suis pas sur que tu aies compris le principe de la solution : Pour récuperer un nombre avec n décimales, on fait (int) ((x*10^n)+0.5) (où 10^n est 10 à la puissance n, pas 10 xor n), et pour que ca marche, il faut et il suffit que x soit connu à 0.5*10^-n près.
Je comprends très bien, mais le sens de l'arrondi n'étant pas défini par C++, j'apportais une nuance (inutile dans le contexte du problème spécifique).
Le message original parlait effectivement de récuperer seulement deux décimales, mais la technique est applicable avec n'importe quel nombre de décimales.
Il y a certaines limites quand même :-)
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Michel Michaud
Dans le message 423dfff9$0$16916$,
Michel Michaud wrote:
C'est exactement à quoi je pensais et ce dont je parlais. La valeur finale, vraiment stockée, peut être plus grande.
Mais de quoi ?
Pour un lecteur humain, la valeur affichée par
cout << fixed << setprecision(30) << 17.58;
pourra être exactement 17.58, plus petite que 17.58 ou plus grande que 17.58. Si elle est plus grande, qu'on multiplie par une puissance de 10 pour penser obtenir la dernière décimale significative et qu'on ajoute 0.5 avant de tronquer en entier, on pourra obtenir une valeur plus grande.
Je ne dis pas que c'est grave, ni que c'est un problème, simplement que la valeur qui est stockée n'étant pas exactement 17.58 et qu'il est donc impossible de savoir si c'était 17.58 qu'on voulait stocker ou si c'est la valeur qui est vraiment stockée...
(Par ailleurs, je signale que le nombre de décimales n'est pas le vrai enjeu, c'est plutôt le nombre de chiffres significatifs. Avec les représentations communes sur 32 bits, il est utopique de penser retrouver les deux décimales de 123456789.01 par exemple...)
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
Dans le message 423dfff9$0$16916$636a15ce@news.free.fr,
Michel Michaud wrote:
C'est exactement à quoi je pensais et ce dont je parlais. La
valeur finale, vraiment stockée, peut être plus grande.
Mais de quoi ?
Pour un lecteur humain, la valeur affichée par
cout << fixed << setprecision(30) << 17.58;
pourra être exactement 17.58, plus petite que 17.58 ou plus grande
que 17.58. Si elle est plus grande, qu'on multiplie par une puissance
de 10 pour penser obtenir la dernière décimale significative et qu'on
ajoute 0.5 avant de tronquer en entier, on pourra obtenir une valeur
plus grande.
Je ne dis pas que c'est grave, ni que c'est un problème, simplement
que la valeur qui est stockée n'étant pas exactement 17.58 et qu'il
est donc impossible de savoir si c'était 17.58 qu'on voulait stocker
ou si c'est la valeur qui est vraiment stockée...
(Par ailleurs, je signale que le nombre de décimales n'est pas le
vrai enjeu, c'est plutôt le nombre de chiffres significatifs. Avec
les représentations communes sur 32 bits, il est utopique de penser
retrouver les deux décimales de 123456789.01 par exemple...)
--
Michel Michaud mm@gdzid.com
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
C'est exactement à quoi je pensais et ce dont je parlais. La valeur finale, vraiment stockée, peut être plus grande.
Mais de quoi ?
Pour un lecteur humain, la valeur affichée par
cout << fixed << setprecision(30) << 17.58;
pourra être exactement 17.58, plus petite que 17.58 ou plus grande que 17.58. Si elle est plus grande, qu'on multiplie par une puissance de 10 pour penser obtenir la dernière décimale significative et qu'on ajoute 0.5 avant de tronquer en entier, on pourra obtenir une valeur plus grande.
Je ne dis pas que c'est grave, ni que c'est un problème, simplement que la valeur qui est stockée n'étant pas exactement 17.58 et qu'il est donc impossible de savoir si c'était 17.58 qu'on voulait stocker ou si c'est la valeur qui est vraiment stockée...
(Par ailleurs, je signale que le nombre de décimales n'est pas le vrai enjeu, c'est plutôt le nombre de chiffres significatifs. Avec les représentations communes sur 32 bits, il est utopique de penser retrouver les deux décimales de 123456789.01 par exemple...)
-- Michel Michaud http://www.gdzid.com FAQ de fr.comp.lang.c++ : http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/