双精度转整型避免损失精度

3
以下声明导致我在编译时出现错误:“错误:(19,13)java:不兼容的类型:可能会丢失从double到int的转换”。
int i1 = 10.0;

// Error:(19, 14) java: incompatible types: possible lossy conversion from double to int

问题1

我理解这个错误,但编译器不能在这种特定情况下推断出不会有精度损失吗?

问题2

如果我将double显式转换为int,那么它可以编译通过(甚至没有警告),尽管在这个例子中我肯定会失去精度。

int i2 = (int)9999999999999.999999999;

如果我无法编译第一个情况 - 在这种情况下不会发生任何损失 - 那么为什么这个具有明确转换的第二个示例甚至没有生成编译器警告?


第一个表达式是编译时错误,它说“类型不匹配:无法从double转换为int”。 - S.K.
4
因为这就是定义Java语言的人所定义的。 - Max Vollmer
1
可能是精度丢失 - int -> float或double的重复问题。 - S.K.
第一种情况类似于一个接受 int 的方法被传递了一个 double 作为参数的情况。两个程序员可能会涉及其中一个定义方法,另一个将浮点值作为参数传递给该方法。两个程序员都可能不知道对方定义方法和调用方法的意图。编译器会报错,因此第二个程序员可以自己将浮点数转换为整数。第二种类型转换的情况是明确的,程序员知道自己在做什么,他是有意进行类型转换的。 - nits.kk
4个回答

2

理论上,编译器可以推断出#1中的具体示例不会因为文字值而失去精度,但正如您所见 - 它没有。

显式转换向编译器发出信号,表明您已经意识到了这种情况并加以处理,因此代码实际上是可以编译的。然而,大多数IDE都可以配置为在这种情况下发出警告。


感谢您的帮助。 - JamieP

2
将一个double值分配给一个int变量需要进行缩小转换,即使该值是编译时常量,因此需要显式转换。 但是,如果常量实际上适合变量值范围,那么可以将int(或shortchar)常量值分配给byteshortchar变量而不需要转换,这在Java语言规范的第5.2节。赋值上下文中有明确说明。
“赋值上下文”允许将表达式的值(§15.26)赋给变量;表达式的类型必须转换为变量的类型。 赋值上下文允许使用以下之一: - 相同类型转换(§5.1.1) - 扩展原始类型转换(§5.1.2) - 扩展引用类型转换(§5.1.5) - 装箱转换(§5.1.7),可随后跟随扩展引用类型转换 - 拆箱转换(§5.1.8),可随后跟随扩展原始类型转换。 如果应用了上述转换后,结果类型是裸类型(§4.8),则可以应用未经检查的转换(§5.1.9)。 另外,如果表达式是类型为byteshortcharint的常量表达式(§15.28,则可以使用以下其中之一: - 如果变量的类型为byteshortchar,并且常量表达式的值可以在变量的类型中表示,则可以使用缩小原始类型转换。 - 如果变量的类型为: - Byte,并且常量表达式的值可以表示为byte类型,则可以使用缩小原始类型转换后跟随装箱转换。 - Short,并且常量表达式的值可以表示为short类型,则可以使用缩小原始类型转换后跟随装箱转换。 - Character,并且常量表达式的值可以表示为char类型,则可以使用缩小原始类型转换后跟随装箱转换。

感谢您的帮助。 - JamieP

1

问题1的答案

根据编译器的看法,存在精度损失,因为编译器只看到你左边有一个int变量,右边有一个double值。编译器并不聪明,不能推断出当转换为int时10.0不会损失精度。

理论上,编译器可以被构建成允许该语句编译通过,但这样做没有实际好处。几乎没有人写int x = 10.0

问题2的答案

确实存在精度损失,但为什么编译器没有抱怨呢?因为您使用了强制类型转换。您写了(int)。这表明您向编译器展示了您知道自己在做什么。通过编写强制类型转换,您告诉它您意识到可能存在精度损失。


当你执行 short s = 12 时,12 是 int 类型的,编译器可以推断没有精度丢失... - Eugene
@Eugene 是的,没错。这是我的猜测:short s = 12int x = 10.0 更有意义。后者感觉很奇怪 - 把小数赋值给整数,而前者是把整数赋值给整数,这就是为什么编译器设计允许前者的原因。 - Sweeper
如果编译器比我们聪明,等等... :) - Eugene
感谢您的帮助。 - JamieP

1

有趣的问题

理论上这是可能的,javac 在执行以下操作时不会报错:

short s = 12;

即使这里的12是一个编译时int类型的常量,因此可以推断出没有丢失精度。我想这就是编译器团队认为最合适的做法。
当你进行cast时情况就不同了,就像在说“相信我,我知道我在做什么”,即使你失去了精度。

谢谢,我本来会接受你的答案的,但我想 Sweeper 在你之前回答了。 - JamieP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接