comportement Varier pour une éventuelle perte de précision
-
01-10-2019 - |
Question
En Java, lorsque vous faites
int b = 0;
b = b + 1.0;
Vous obtenez une possible perte d'erreur de précision. Mais pourquoi est-ce que si vous faites
int b = 0;
b += 1.0;
Il n'y a pas d'erreur?
La solution
C'est parce que b += 1.0;
équivaut à b = (int) ((b) + (1.0));
. Les rétrécissement conversion primitive (JLS 5.1.3) est caché dans l'opération d'affectation de composé.
JLS 15,26. 2 opérateurs d'affectation composés (JLS Troisième édition):
Une expression d'affectation de composé de la forme E1 op = E2 est équivalent à E1 = (T) ((E1) op (E2)) , où T est le type de E1 , sauf que E1 est évalué qu'une seule fois.
Par exemple, le code suivant est correct:
short x = 3; x += 4.6;
et des résultats dans
x
ayant la valeur7
parce qu'il est équivalent à:short x = 3; x = (short)(x + 4.6);
Cela explique aussi pourquoi les compiles de code suivant:
byte b = 1;
int x = 5;
b += x; // compiles fine!
Mais cela ne fait pas:
byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!
Vous devez explicitement jeter dans ce cas:
byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!
Il convient de noter que la distribution implicite dans les affectations composés fait l'objet de Puzzle 9: Tweedledum dans le merveilleux livre Java Puzzlers . Voici quelques extraits du livre (légèrement modifié par souci de concision):
De nombreux programmeurs pensent que
.x += i;
est tout simplement un raccourci pourx = x + i;
. Ce n'est pas tout à fait vrai: si le type du résultat est plus large que celle de la variable, l'opérateur d'affectation composé effectue un rétrécissement silencieux conversion primitivePour éviter les mauvaises surprises, ne pas utiliser les opérateurs d'affectation composés sur des variables de type
byte
,short
ouchar
. Lors de l'utilisation des opérateurs d'affectation composés sur des variables de typeint
, assurez-vous que l'expression sur le côté droit est pas de typelong
,float
oudouble
. Lors de l'utilisation des opérateurs d'affectation composés sur des variables de typefloat
, assurez-vous que l'expression sur le côté droit est pas de typedouble
. Ces règles sont suffisantes pour empêcher le compilateur de générer des moulages de rétrécissement dangereux.Pour les concepteurs de la langue, il est probablement une erreur pour les opérateurs d'affectation composés pour générer des moulages invisibles; missions composées où la variable a un type plus étroit que le résultat du calcul devrait probablement être illégal.
Le dernier paragraphe est intéressant de noter: C # est beaucoup plus stricte à cet égard (voir C # Language Specification 7.13.2 affectation composé ).