为什么Java隐式(不强制转换)将“long”转换为“float”?

2022-08-31 22:18:55

每当我认为自己了解了选角和转换时,我就会发现另一种奇怪的行为。

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

鉴于 a 比 a 具有更大的位深度,我预计需要一个显式的强制转换才能进行编译。毫不奇怪,我们看到我们在结果中失去了精确度。longfloat

为什么这里不需要演员表?


答案 1

可以提出相同的问题 - 两次转换都可能丢失信息。longdouble

Java语言规范的第5.1.2节说:

加宽基元转换不会丢失有关数值总体大小的信息。实际上,从一个整数类型扩展到另一个整数类型的转换根本不会丢失任何信息;该数值将精确保留。在 strictfp 表达式中,从浮点型扩大到双精度型的转换也会精确地保留数值;但是,此类非严格fp的转换可能会丢失有关转换值的总体大小的信息。

将 int 或长整型值转换为浮点型,或将长整型值转换为双精度值,可能会导致精度损失,也就是说,结果可能会丢失值的某些最低有效位。在这种情况下,生成的浮点值将是整数值的正确舍入版本,使用 IEEE 754 舍入到最近模式 (§4.2.4)。

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

当然,可以选择要求所有隐式转换根本不丢失任何信息-因此,并且本来是显式的,并且本来是显式的。(to 是可以的;a 具有足够的精度来准确表示所有值。intlongfloatlongdoubleintdoubledoubleint

在某些情况下,这将是有用的 - 在某些情况下不是。语言设计是关于妥协的;有得必有失。我不确定我会做出什么决定...


答案 2

Java 语言规范第 5 章:转换和升级解决了这个问题:

5.1.2 加宽基元转换

基元类型的以下 19 个特定转换称为加宽基元转换:

  • 字节到短整型、整型、长整型、浮点型或双精度型
  • 短到整型、长整型、浮点型或双精度型
  • 字符到整型、长整型、浮动型或双精度型
  • 整型到长整型、浮点型或双精度型
  • 长至浮动或双倍
  • 浮点到双倍

加宽基元转换不会丢失有关数值总体大小的信息。

...

将 int 或长整型值转换为浮点型,或将长整型值转换为双精度值,可能会导致精度损失,也就是说,结果可能会丢失值的某些最低有效位。在这种情况下,生成的浮点值将是整数值的正确舍入版本

换句话说,JLS区分了幅度损失和精度损失。

int例如,to 是(潜在的)量级损失,因为您无法在 .bytebyte

longto 是精度的潜在损失,但不是幅度,因为浮点数的值范围大于多头的值范围。float

所以规则是:

  • 数量级损失:需要显式投射;
  • 精度损失:无需铸造。

微妙?确定。但我希望这能澄清这一点。


推荐