Question

J'ai un flotteur primitif et j'ai besoin comme un double primitif. Il suffit de jeter le flotteur à doubler me donne une précision supplémentaire bizarre. Par exemple:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

Cependant, si au lieu de coulée, je sortie le flotteur sous forme de chaîne, et analyser la chaîne en double, je reçois ce que je veux:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

Y at-il une meilleure façon que d'aller à cordes et à l'arrière?

Était-ce utile?

La solution

Il est pas que vous êtes en fait obtenir une précision supplémentaire - il est que le flotteur ne représente pas exactement le nombre que vous visiez à l'origine. Le double représentant la précision float d'origine; toString montre les données « extra » qui était déjà présent.

Par exemple (et ces chiffres ne sont pas bien, je fais juste les choses) suppose que vous aviez:

float f = 0.1F;
double d = f;

Alors peut-être exactement 0,100000234523 la valeur de f. d aura exactement la même valeur, mais quand vous le convertir en une chaîne, il sera « confiance » qu'elle est exacte à une plus grande précision, donc ne seront pas arrondir le plus tôt, et vous verrez les « chiffres supplémentaires » qui étaient déjà là, mais caché.

Lorsque vous passez à une chaîne et en arrière, vous se retrouver avec une double valeur qui est plus proche de la valeur de chaîne que le flotteur d'origine était - mais c'est seulement bon si vous croyez vraiment que la valeur de chaîne est ce que vous vouliez vraiment.

Êtes-vous sûr que flotteur / deux sont les types appropriés à utiliser ici au lieu de BigDecimal? Si vous essayez d'utiliser les numéros qui ont des valeurs décimales précises (par exemple l'argent), alors BigDecimal est un type plus approprié de l'OMI.

Autres conseils

Je trouve la conversion à la représentation binaire plus facile à saisir ce problème.

float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;

System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));

Vous pouvez voir le flotteur est étendu au double en ajoutant 0s à la fin, mais que la double représentation de 0,27 est « plus précis », d'où le problème.

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

Ceci est dû au contrat de Float.toString(float), qui dit en partie:

  

Combien de chiffres doit être imprimé pour   la partie décimale [...]? Là   doit être d'au moins un chiffre à   représentent la partie décimale, et   au-delà comme beaucoup, mais seulement comme beaucoup,    plus de chiffres que nécessaire pour unique   distinguer la valeur de l'argument de   valeurs adjacentes de type float. Ce   est, supposons que x est l'exacte   valeur mathématique représenté par la   représentation décimale produite par   cette méthode pour un fini non nul   f argument. Alors f doit être le flotteur   La valeur la plus proche de x; ou, si deux flotteurs   Les valeurs sont tout aussi proche de x, f   doit être l'un d'entre eux et le moins   peu significatif du significand de   f doit être 0.

Je l'ai rencontré ce problème aujourd'hui et ne pouvait pas utiliser refactor à BigDecimal, parce que le projet est vraiment énorme. solution mais j'ai trouvé en utilisant

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

Et cela fonctionne.

Notez que l'appel retourne result.doubleValue () 5623,22998046875

Mais l'appel retourne correctement 5623,23 doubleResult.doubleValue ()

Mais je ne suis pas tout à fait sûr si sa une solution correcte.

Utilisez un BigDecimal au lieu de float / double. Il y a beaucoup de chiffres qui ne peuvent pas être représentés en tant que point flottante binaire (par exemple, 0.1). Donc, vous devez soit toujours arrondir le résultat à une précision connue ou utilisez BigDecimal.

Voir http://en.wikipedia.org/wiki/Floating_point pour plus d'informations .

J'ai trouvé la solution suivante:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

Si vous utilisez float et à double au lieu de Float et Double utiliser les éléments suivants:

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

Flotteurs, par nature, sont imprécises et ont toujours arrondi purs « problèmes ». Si la précision est importante, alors vous pourriez envisager de refactorisation votre application à utiliser décimale ou BigDecimal.

Oui, flotteurs sont informatiquement plus vite que les décimales en raison du support sur processeur. Cependant, voulez-vous rapide ou précis?

Pour en savoir plus c'est sous le point 48 - Évitez float et double lorsque les valeurs exactes sont nécessaires, de Effective Java 2e édition par Joshua Bloch. Ce livre est bourré de bonnes choses et un look vraiment la peine.

Est-ce que ce travail?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top