不同的行为可能会导致精度损失

发布于 2024-08-29 18:59:05 字数 171 浏览 2 评论 0 原文

在 Java 中,当你这样做时

int b = 0;
b = b + 1.0;

,你可能会遇到精度损失错误。但为什么如果你这么做了

int b = 0;
b += 1.0;

却没有任何错误呢?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

葵雨 2024-09-05 18:59:05

这是因为 b += 1.0; 相当于 b = (int) ((b) + (1.0));缩小原始转换 (JLS 5.1 .3)隐藏在复合赋值操作中。

JLS 15.26.2 复合赋值运算符(JLS 第三版):

E1 op= E2 形式的复合赋值表达式相当于 E1 = (T)((E1) op (E2)),其中 TE1 的类型,但 E1 仅计算一次。

例如,下面的代码是正确的:

短 x = 3;
x+=4.6;

并导致x的值为7,因为它相当于:

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

这也解释了为什么以下代码可以编译:

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

但这并不' t:

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

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

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

值得注意的是,复合赋值中的隐式强制转换是《Puzzle 9: Tweedledum》的主题,来自精彩的书 Java Puzzlers。以下是本书的一些摘录(为简洁起见,略有编辑):

许多程序员认为x += i;只是x = x + i;的简写。这并不完全正确:如果结果的类型比变量的类型宽,则复合赋值运算符会执行静默缩小原始转换。

为了避免令人不快的意外,不要对类型为 byteshortchar 的变量使用复合赋值运算符代码>.对 int 类型的变量使用复合赋值运算符时,请确保右侧表达式的类型不是 longfloat、或。对 float 类型的变量使用复合赋值运算符时,请确保右侧的表达式不是 double 类型。这些规则足以防止编译器生成危险的窄化强制转换。

对于语言设计者来说,复合赋值运算符生成不可见的强制转换可能是一个错误;变量的类型比计算结果窄的复合赋值可能是非法的。

最后一段值得注意:C# 在这方面要严格得多(请参阅 C# 语言规范 7.13.2 复合赋值)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文