9 votes

Comparaison des primitives float et double en Java

Je suis tombé sur un coin étrange de Java. (Il me semble étrange)

double dd = 3.5;          
float ff = 3.5f;
System.out.println(dd==ff);   

o/p : vrai

double dd = 3.2;
float ff = 3.2f;
System.out.println(dd==ff);

o/p : faux

J'ai observé que si nous comparons deux valeurs quelconques (un float et un double comme je l'ai mentionné dans l'exemple) avec .5 OU .0 comme 3.5, 234.5, 645.0 alors la sortie est true i.e. deux valeurs sont égales sinon la sortie est false bien qu'ils soient égaux.

Même moi, j'ai essayé de faire de la méthode strictfp mais pas de chance. Est-ce que je rate quelque chose ?

20voto

Edwin Buck Points 33097

Jetez un coup d'œil à Ce que tout informaticien devrait savoir sur les nombres à virgule flottante .

Pour faire tenir une infinité de nombres réels dans un nombre fini de bits, il faut une représentation approximative.....

--- Modifier pour montrer ce que signifie la citation ci-dessus ---

Vous ne devriez jamais comparer des flottants ou des doubles pour l'égalité, car vous ne pouvez pas vraiment garantir que le nombre que vous attribuez au flottant ou au double est exact.

Alors

 float x = 3.2f;

n'aboutit pas à un nombre flottant dont la valeur est 3,2. Le résultat est un flottant dont la valeur est de 3,2 plus ou moins une très petite erreur. Disons 3.19999999997f. Maintenant, la raison pour laquelle la comparaison ne fonctionne pas devrait être évidente.

Pour comparer des flottants de manière rationnelle, vous devez vérifier si la valeur est "suffisamment proche" de la même valeur, comme suit

float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
   // close enough that we'll consider the two equal
   ...
}

10voto

Jon Skeet Points 692016

La différence est que 3,5 peut être représenté exactement dans les deux float y double - alors que 3.2 ne peut être représenté exactement dans aucun des deux types... et les deux approximations les plus proches sont différentes.

Imaginons que nous ayons deux systèmes à précision fixe décimal L'un d'entre eux stockait 4 chiffres significatifs et l'autre 8 chiffres significatifs, et nous avons demandé à chacun d'entre eux de stocker le nombre le plus proche d'"un tiers" (quelle que soit la façon dont nous le faisons). L'un d'eux aurait alors la valeur 0,3333 et l'autre la valeur 0,33333333.

Une comparaison d'égalité entre float y double convertit d'abord le float à un double et compare ensuite les deux - ce qui équivaudrait à convertir 0,3333 dans notre type "petites décimales" en 0,33330000. Il compare alors 0,33330000 et 0,33333333 pour vérifier l'égalité, et donne un résultat faux.

3voto

Kerrek SB Points 194696

L'implémentation commune des nombres à virgule flottante, IEEE754, permet une représentation précise des seuls nombres qui ont une valeur de expansion binaire courte et finie c'est-à-dire qui sont une somme d'un nombre fini de puissances de deux (proches). Tous les autres nombres ne peuvent pas être représentés avec précision.

Desde float y double ont des tailles différentes, la représentation dans les deux types pour une valeur non représentable est différente, et ils se comparent donc comme inégaux.

(Le longueur de la chaîne binaire est la taille de la mantisse, donc c'est 24 pour float 53 pour double et 64 pour le flottant à précision étendue de 80 bits (pas en Java). Le site échelle est déterminé par l'exposant).

3voto

Peter Lawrey Points 229686

La virgule flottante est un format binaire qui peut représenter les nombres comme une somme de puissances de 2. Par exemple, 3,5 est 2 + 1 + 1/2.

flotter 3.2f comme une approximation de 3.2 est

2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/4194304 + a small error

Cependant, le double de 3.2d comme une approximation de 3.2 est

2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/8388608+ 1/16777216+ 1/134217728+ 1/268435456+ 1/2147483648+ 1/4294967296+ 1/34359738368+ 1/68719476736+ 1/549755813888+ 1/1099511627776+ 1/8796093022208+ 1/17592186044416+ 1/140737488355328+ 1/281474976710656+ 1/1125899906842624 + a smaller error

Lorsque vous utilisez la virgule flottante, vous devez utiliser les arrondis appropriés. Si vous utilisez BigDecimal à la place (et beaucoup de gens le font), l'arrondi est intégré.

double dd = 3.2;          
float ff = 3.2f;
// compare the difference with the accuracy of float.
System.out.println(Math.abs(dd - ff) < 1e-7 * Math.abs(ff));

BTW le code que j'ai utilisé pour imprimer les fractions pour double.

double f = 3.2d;
double f2 = f - 3;
System.out.print("2+ 1");
for (long i = 2; i < 1L << 54; i <<= 1) {
  f2 *= 2;
  if (f2 >= 1) {
    System.out.print("+ 1/" + i);
    f2 -= 1;
  }
}
System.out.println();

0voto

Mike Argyriou Points 101

Cela devrait fonctionner :

BigDecimal ddBD = new BigDecimal(""+dd);
BigDecimal ffBD = new BigDecimal(""+ff);

// test for equality
ddBO.equals(ffBD);

Travaillez toujours avec BigDecimal lorsque vous voulez comparer des flottants ou des doubles et utilisez toujours le constructeur BigDecimal avec l'attribut Paramètre de type chaîne !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X