Bonjour à tous,
Je crois que cette curiosité n'est pas spécifique à JAVA mais je la pose quand même :
pourquoi :
System.out.println(100.0*1.1);
donne :
110.00000000000001
?? 8O
que faire pour avoir le bon résultat?
A+
Version imprimable
Bonjour à tous,
Je crois que cette curiosité n'est pas spécifique à JAVA mais je la pose quand même :
pourquoi :
System.out.println(100.0*1.1);
donne :
110.00000000000001
?? 8O
que faire pour avoir le bon résultat?
A+
Salut,
Les nombres flottants correspondent à des approximations, car il est tout bonnement impossible de représenter tous les nombres flottants sur une zone mémoire limité... car on peut toujours rajouté une décimales :aie:
:arrow: Essayes de représenter tous les nombres flottant entres 0.0 et 1.0 et tu verras le problème ;)
Donc on a affaire à des approximations sur la partie flottante, basé sur une norme (IEEE 754) intégré dans tous les processeurs actuels. Ainsi chez moi 1.1 vaut en réalité 1.100000000000000088817841970012523233890533447265625.
Le problème étant qu'avec certains calcul cette approximation peut s'accumuler et amener des erreurs. Il faut ainsi arrondir les résultats pour éviter les erreurs les plus courantes.
Mais si on veut un calcul précis, il faut utiliser des BigDecimal (ce qui implique également un code plus lourd :() :
Attention à ne pas initialiser les BigDecimal avec un double ou un float, car sinon on conserve l'approximation :Code:System.out.println( new BigDecimal("1.1").multiply(new BigDecimal("100.0")) );
Code:System.out.println( new BigDecimal(1.1) ); // 1.100000000000000088817841970012523233890533447265625
a++
Et dans le cas ou tu preferes rester avec des types de base, le probleme de l'affichage se resoud en utilisant un formatteur pour l'affichage. Voir NumberFormat et DecimalFormat (ceci ne fait que cacher le manque de precision, le probleme est toujours present).
mmm 2^-50 donne ceci:
8.8817841970012523233890533447265625E-16
la 50ème décimale binaire de la mantise nécessite donc 52 décimales en base 10 :)
la transformation flottant -> décimal peut toujours etre faite de manière exacte, car on peut représenter en décimal toutes les puissance négatives de 2. Par contre, on ne peux pas représenter en somme puissance de 2 tous les nombres décimaux. :)
Hi,
Alors j'en conclu que le calcul est effectué avec un type plus grand que double, car 2^50 fait 1125899906842624, soit environ 10^17, ce qui est donc la limite en chiffres décimaux pour ce type.
il ne s'agit pas de 2^50 mais de 2^-50 !
c'est pas parce que tu a besoin de n chiffre pour répresenter un nombre X que tu as beosin de ~n chiffre pour représenter 1/n
et en l'occurence 1/1125899906842624 donne bien
8.881784197001252323389053344726562500000000000000000000000000000000000000000000000000E-16
donc les chiffre significatif d'adiguba sont bel est bien corrects pour représenter exactement le flottant :)Code:
1
2
3
4
5
6
7 public class Test { public static void main(String[] argv){ BigDecimal bd = new BigDecimal("1"); bd=bd.setScale(100); System.out.println("1/2^50="+bd.divide(new BigDecimal("1125899906842624""),BigDecimal.ROUND_UNNECESSARY)); } }
C'est juste que d'habitue on arrondi au quelques décimale pour garder la cohérence avec la mathématique en base 10 :)
Gei,
BigDecimal, alors que je te parle du type double. Essaie, et tu verras bien.
Ben justement avec ce code on transforme un double en BigDecimal, ce qui fait que l'on obtient l'approximation de la valeur du double :
Mais comme tu l'as dit il n'y a que 16 chiffres significatif, ce qui nous donne en fait : 1.100000000000000088817841970012523233890533447265625 soit 1.1Code:System.out.println( new BigDecimal(1.1) ); // 1.100000000000000088817841970012523233890533447265625
Le problème vient justement de ces chiffres après qui ne sont pas signification, mais qui fausse légèrement le résultat de certain calcul...
Avec BigDecimal on manipule les vrai valeurs complète, et on perçoit mieux le problème ;)
a++
Je remets ce sujet à l'ordre du jour parce que je viens de me heurter au problème.
Je n'ai pas d'objection à utiliser BigDecimal et à lui donner des String en paramètre, mais est-ce que ceci implique que les données dans la base de données doivent être stockées en tant que String aussi?
non tu peux te contente d'utiliser des formatter qui on une précision inférieur à ton erreur de calcul, et le tour est joué, l'utilisateur ne vois pas l'impressicion