2010-03-05 9 views
1

J'ai un problème préoccupé par perdre de précisionJava perte de précision

ma tâche est d'imprimer des nombres sous forme de chaînes

int exponent = ... 
int[] Mantissas = { 1, 2, 5 }; 
double dataStep = java.lang.Math.pow(10.0, exponent) * Mantissas[mantissaIndex]; 
... 
for (int i = 0; i < NSteps; i++) 
        steps[i] = firstStep + i * dataStep; 
draw(steps); 

par exemple, 0,2 * 7 = 1,4000000000000001; 0.0000014/10 = 1.3999999999999998E-7

Comment résoudre ce problème?

UPD: Le principal problème est string formateur de sortie. je ne dérange pas de perdre environ 0,00000001 valeur. Maintenant, je résolus comme String.format (« % f », valeur), mais je pense que ce n'est pas une bonne approche

+3

La question la plus fréquemment posée sur l'ensemble de stackoverflow. – mob

+0

Nous devrions avoir un badge fubar pour poser cette question. –

Répondre

3

Comme mentionné par d'autres, vous devez utiliser java.math.BigDecimal au lieu de float/double. Ceci vient cependant avec son propre ensemble de problèmes.

Par exemple lorsque vous appelez BigDecimal (double) la valeur que vous passez sera élargi à sa pleine représentation:

BigDecimal oneTenth = new BigDecimal(0.1); 
BigDecimal oneMillion = new BigDecimal(1000000); 
oneTenth.multiply(oneMillion) 
out> 100000.0000000000055511151231257827021181583404541015625000000 

Mais lorsque vous utilisez le constructeur BigDecimal (String) la valeur EACT est représentée et vous obtenir

BigDecimal oneTenth = new BigDecimal("0.1"); 
BigDecimalr oneMillion = new BigDecimal(1000000); 
oneTenth.multiply(oneMillion) 
out> 100000.0 

Vous pouvez en savoir plus sur les limites de BigDecimal dans magnifique livre Java puzzlers de Joshua Bloch et Neal Gafter et this article informatif. Notez enfin que toString on BigDecimal s'imprimera en notation scientifique, donc vous devrez utiliser toPlainString.

2

Le type double n'a pas une précision infinie et ne peut pas représenter exactement décimaux. Vous observez des erreurs d'arrondi normales. Pour l'arithmétique de précision arbitraire, vous devrez utiliser java.math.BigDecimal à la place.

+0

ok, java.math.BigDecimal m = nouveau BigDecimal (1.4) .setScale (1000); m = m.divide (nouveau BigDecimal (10) .setScale (1000)); \t \t System.out.println (m); la sortie est 0.1399999999999999911182158029987476766109466552734375 , je veux imprimer "0.14" sur mon tableau de contrôle – 2xMax

+0

Ne pas utiliser de nouvelles BigDecimal (double) soit BigDecimal nouvelle (chaîne) ou BigDecimal.valueOf (double). Le nouveau BigDecimal (double) agira exactement comme un double. – ILMTitan

Questions connexes