关于java:可能损失精度的不同行为

Varying behavior for possible loss of precision

当你在JavaP></

1
2
int b = 0;
b = b + 1.0;

你得到的可能损失的精度误差。为什么是它,但如果你给P></

1
2
int b = 0;
b += 1.0;

不有任何错误吗?P></


这是因为b += 1.0;相当于b = (int) ((b) + (1.0));。压缩原始转换(jls 5.1.3)隐藏在复合赋值操作中。

JLS 15.26.2化合物分配操作员(JLS第三版):

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:

1
2
short x = 3;
x += 4.6;

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

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

这也解释了以下代码编译的原因:

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

但这并不是:

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

在这种情况下,需要显式强制转换:

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

值得注意的是,隐含的复合式赋值是谜题9的主题:ToeDeDelm从奇妙的书Java拼图。以下是这本书的一些摘录(为简洁起见稍作编辑):

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.

最后一段值得注意:C在这方面更严格(见C语言规范7.13.2复合赋值)。