可能损失精度的不同行为 [英] Varying behavior for possible loss of precision

查看:28
本文介绍了可能损失精度的不同行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Java 中,当你这样做时

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;

没有任何错误吗?

推荐答案

那是因为 b += 1.0; 等价于 b = (int) ((b) + (1.0));.缩小原语转换 (JLS 5.1.3) 隐藏在复合赋值操作中.

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.

E1 op= E2 形式的复合赋值表达式等价于 E1 = (T)((E1) op (E2)),其中 TE1 的类型,除了 E1 只计算一次.

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;

并导致 x 的值为 7 因为它等价于:

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!

但这不会:

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!


值得注意的是,复合赋值中的隐式转换是难题 9:Tweedledum 的主题,来自精彩的书籍 Java 拼图.以下是书中的一些摘录(为简洁起见略有编辑):


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

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

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.

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

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 复合赋值).

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

这篇关于可能损失精度的不同行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆