为什么Java隐式(没有强制转换)将`long`转换为`float`?

时间:2009-08-18 13:26:43

标签: java casting

每当我想到我对转换和转换的理解时,我发现了另一种奇怪的行为。

long l = 123456789L;
float f = l;
System.out.println(f);  // outputs 1.23456792E8

鉴于long的位深度大于float,我希望为了编译它,需要进行显式转换。毫不奇怪,我们发现结果已经失去了精确度。

为什么这里不需要演员?

4 个答案:

答案 0 :(得分:43)

可能会问longdouble同样的问题 - 这两次转换都可能会丢失信息。

Section 5.1.2 of the Java Language Specification说:

  

扩展原始转换不会   丢失有关整体的信息   数值的大小。确实,   转换从一个整体扩大   类型到另一个整数类型不   丢失任何信息;该   数值完全保留。   转换从浮动扩展到   strictfp表达式也加倍   准确保存数值;   但是,这种转换不是   strictfp可能会丢失有关的信息   转换后的整体幅度   值。

     

转换int或long值   浮动,或长期价值   加倍,可能导致损失   精度 - 也就是说,结果可能会丢失   一些最不重要的部分   价值。在这种情况下,由此产生   浮点值将是一个   正确的圆形版本   整数值,使用IEEE 754   舍入到最接近的模式(§4.2.4)。

换句话说,即使您可能丢失信息,您也知道该值仍将在目标类型的整个范围内。

当然可以选择要求所有隐式转换都不会丢失任何信息 - 因此intlongfloat将是明确的longdouble本来就是明确的。 (intdouble没问题; double有足够的精确度来准确表示所有int值。)

在某些情况下本来有用 - 在某些情况下不是。语言设计是妥协;你无法赢得所有人。我不确定我做出了什么决定......

答案 1 :(得分:39)

Java Language Specification, Chapter 5: Conversion and Promotion解决了这个问题:

  

5.1.2加宽原始转换

     

以下19项具体转换   原始类型称为   拓宽原始转换:

     
      
  • byte to short,int,long,float或double
  •   
  • 简称为int,long,float或double
  •   
  • char to int,long,float或double
  •   
  • int to long,float或double
  •   
  • 长期漂浮或加倍
  •   
  • 浮动加倍
  •   
     

扩展原始转换不会丢失有关数值整体大小的信息。

     

...

     

将int或long值转换为float,或将long值转换为double,可能会导致精度损失 - 也就是说,结果可能会丢失该值的一些最低有效位。在这种情况下,生成的浮点值将是整数值

的正确舍入版本

换句话说,JLS区分 幅度 的丢失和 精度 的丢失

intbyte例如是(潜在的)数量级的损失,因为您无法在byte中存储500个。

longfloat可能会导致精度损失,但幅度不大,因为浮点数的值范围大于longs的值。

所以规则是:

  • 失去规模:需要明确投射;
  • 精度损失:无需强制转换。

微妙?当然。但我希望能够解决这个问题。

答案 2 :(得分:14)

虽然你在内部使用多于一个浮点的内容是正确的,但java语言在扩展路径上工作:

字节 - >短 - > int - >长 - >浮动 - >双

要从左向右转换(扩展转换),不需要强制转换(这就是允许浮动长度的原因)。要从右向左转换(缩小转换),必须进行显式转换。

答案 3 :(得分:2)

某处我听到了这个。 Float可以像我们编写的那样以指数形式存储。 ' 235亿'存储为' 2.35e10'那么,float有空间占据long的值范围。以指数形式存储也是精确丢失的原因。