2011-08-16 4 views
3

Je suis assez confus au sujet de cette "erreur" particulière que j'obtiens en analysant une chaîne à un double.NumberFormat Parse Problème

J'ai déjà configuré les propriétés et symboles NumberFormat.

Lors du passage d'une chaîne de 15 chiffres et 2 décimales (ex. str = "333333333333333,33") et l'analyse avec le résultat Number num = NumberFormat.parse(str) omet un chiffre.

La valeur réelle de num est 3.333333333333333E14.

Il semble travailler avec des chaînes avec tous des 1, 2 et 4 de ce que ...

Tout le monde peut me éclairer?

Vive Enrico

Répondre

5

La méthode DecimalFormat.parse sera dans ce cas un retour Double, qui a une précision limitée .

Vous ne pouvez pas vous attendre à toujours pouvoir renvoyer un nombre qui représente l'entrée exactement.

Vous pouvez utiliser BigDecimal.setParseBigDecimal pour permettre au format numérique pour revenir un BigDecimal de la méthode d'analyse syntaxique. Ce Number est capable de représenter vos valeurs avec une précision arbitraire. (Merci @Peter Lawrey de l'avoir signalé!)

+0

Y a-t-il une solution de contournement pour éviter de doubler mais de laisser trop long? – Mallinok

+0

Un 'long' est un type entier, ainsi vous perdriez la partie fractionnaire (', 33'). – aioobe

+0

@aioobe, Pourriez-vous regarder les documents pour Java 1.4? Cette méthode a été ajoutée en Java 5.0. http://download.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html#setParseBigDecimal%28boolean%29 –

6

La réponse courte; en raison d'une erreur ronde

(double) 111111111111111.11 != (double) 111111111111111.1 

mais

(double) 333333333333333.33 == (double) 333333333333333.3 

Si vous voulez plus de précision, utilisez setParseBigDecimal et Parse retournera un BigDecimal.


Pourquoi cela? C'est parce que vous êtes à la limite de la précision du double. Les 17 sont bien car ils peuvent être représentés. Le 2 est juste le double et comme double stocke les pouvoirs de deux, chaque puissance de deux de tous les 17, donc 17 fours et 17 huit est bien.

Cependant, 17 trois prend un peu plus que le double doit représenter la valeur et ce dernier bit est tronqué. De même, 17 octets, six et neuf ont également des erreurs d'arrondi.

double[] ds = { 
     111111111111111.11, 
     222222222222222.22, 
     333333333333333.33, 
     444444444444444.44, 
     555555555555555.55, 
     666666666666666.66, 
     777777777777777.77, 
     888888888888888.88, 
     999999999999999.99}; 
for (double d : ds) { 
    System.out.println(d + " - " + new BigDecimal(d)); 
} 

affiche les éléments suivants. Le double est légèrement arrondi avant l'impression et le BigDecimal vous montre les valeurs exactes que le double représente.

1.1111111111111111E14 - 111111111111111.109375 
2.2222222222222222E14 - 222222222222222.21875 
3.333333333333333E14 - 333333333333333.3125 
4.4444444444444444E14 - 444444444444444.4375 
5.5555555555555556E14 - 555555555555555.5625 
6.666666666666666E14 - 666666666666666.625 
7.777777777777778E14 - 777777777777777.75 
8.888888888888889E14 - 888888888888888.875 
1.0E15 - 1000000000000000 
+1

+1, réponse awsome. – aioobe

+0

@aioobe, Venant de vous, cela signifie quelque chose. ;) –

+0

heh merci :-) J'ai été tellement surpris au cours de votre deuxième expression, donc j'ai écrit une [question de suivi] (http://stackoverflow.com/questions/7076653/why-is-arbitrary-precision-in-double-literals -allowed-in-java) – aioobe