Varying behavior for possible loss of precision

In Java, when you do

int b = 0;
b = b + 1.0;

You get a possible loss of precision error. But why is it that if you do

int b = 0;
b += 1.0;

There isn't any error?


That's because b += 1.0; is equivalent to b = (int) ((b) + (1.0)); . The narrowing primitive conversion (JLS 5.1.3) is hidden in the compound assignment operation.

JLS 15.26.2 Compound Assignment Operators (JLS Third Edition):

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

For example, the following code is correct:

short x = 3;
x += 4.6;

and results in x having the value 7 because it is equivalent to:

short x = 3;
x = (short)(x + 4.6);

This also explains why the following code compiles:

byte b = 1;
int x = 5;
b += x; // compiles fine!

But this doesn't:

byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!

You need to explicitly cast in this case:

byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!

It's worth noting that the implicit cast in compound assignments is the subject of Puzzle 9: Tweedledum from the wonderful book Java Puzzlers. Here are some excerpt from the book (slightly edited for brevity):

Many programmers think that x += i; is simply a shorthand for x = x + i; . This isn't quite true: if the type of the result is wider than that of the variable, the compound assignment operator performs a silent narrowing primitive conversion.

To avoid unpleasant surprises, do not use compound assignment operators on variables of type byte , short , or char . When using compound assignment operators on variables of type int , ensure that the expression on the right-hand side is not of type long , float , or double . When using compound assignment operators on variables of type float , ensure that the expression on the right-hand side is not of type double . These rules are sufficient to prevent the compiler from generating dangerous narrowing casts.

For language designers, it is probably a mistake for compound assignment operators to generate invisible casts; compound assignments where the variable has a narrower type than the result of the computation should probably be illegal.

The last paragraph is worth noting: C# is a lot more strict in this regard (see C# Language Specification 7.13.2 Compound assignment).


Maybe, and just maybe it is because in the former it is converting b to floating point, then adding, then converting it back to integer ?

And the latter it may be converting 1.0 to integer instead, and doing integer addition?

Just a guess though.

链接地址: http://www.djcxy.com/p/73636.html

上一篇: 为什么Java不支持unsigned int?

下一篇: 变化的行为可能导致精度损失