为了账号安全,请及时绑定邮箱和手机立即绑定

变化的行为可能会降低精度

变化的行为可能会降低精度

FFIVE 2019-10-12 10:10:24
在Java中,当您执行int b = 0;b = b + 1.0;您可能会损失精度误差。但是为什么要这么做int b = 0;b += 1.0;没有任何错误吗?
查看完整描述

1 回答

?
RISEBY

TA贡献1856条经验 获得超5个赞

那是因为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))),其中T是E1的类型,只是E1仅被评估一次。


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


short x = 3;

x += 4.6;

并导致x具有该值,7因为它等效于:


short x = 3;

x = (short)(x + 4.6);

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


byte b = 1;

int x = 5;

b += x; // compiles fine!

但这不是:


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!

值得注意的是,复合赋值中的隐式强制转换是精彩书籍Java Puzzlers中的Puzzle 9:Tweedledum的主题。这是本书的摘录(为简洁起见,对其进行了略作编辑):


许多程序员认为这x += i;仅仅是的简写x = x + i;。事实并非如此:如果结果的类型比变量的类型宽,则复合赋值运算符将执行无声收窄基元转换。


为了避免不愉快的意外,不要类型的变量使用复合赋值运算符 byte,short或char。当类型的变量使用复合赋值运算符int,确保在右手侧的表达式的类型不long,float或double。在类型变量上使用复合赋值运算符时float,请确保右侧的表达式不是type double。这些规则足以防止编译器生成危险的缩小强制类型转换。


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


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


查看完整回答
反对 回复 2019-10-12
  • 1 回答
  • 0 关注
  • 316 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信