繁体   English   中英

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

[英]Why does Java implicitly (without cast) convert a `long` to a `float`?

每次我认为我了解强制转换和转换时,我都会发现另一种奇怪的行为。

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

鉴于longfloat具有更大的位深度,我希望需要显式转换才能编译它。 毫不奇怪,我们发现我们已经失去了结果的精确度。

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

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

5.1.2 扩大原语转换

以下 19 种特定于原始类型的转换称为扩展原始类型转换:

  • 字节到 short、int、long、float 或 double
  • 短到 int、long、float 或 double
  • char 到 int、long、float 或 double
  • int 到 long、float 或 double
  • long 浮动或加倍
  • 浮动到两倍

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

...

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

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

例如intbyte是一个(潜在的)量级损失,因为你不能在一个byte存储 500 。

long to float是精度的潜在损失,但不是数量级,因为 floats 的值范围大于 longs 的值范围。

所以规则是:

  • 量级损失:需要显式转换;
  • 精度损失:不需要铸造。

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

同样的问题可能会被问到longdouble - 两种转换都可能会丢失信息。

Java 语言规范的第 5.1.2 节说:

扩展原始转换不会丢失有关数值整体大小的信息。 实际上,从一个整数类型扩展到另一个整数类型的转换根本不会丢失任何信息; 数值被完全保留。 在strictfp 表达式中从float 扩大到double 的转换也精确地保留了数值; 但是,这种不严格的转换可能会丢失有关转换值的整体大小的信息。

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

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

当然可以选择要求所有隐式转换完全不丢失任何信息 - 因此intlongfloat将是显式的,而longdouble将是显式的。 intdouble是可以的; double具有足够的精度来准确表示所有int值。)

在某些情况下这会很有用 - 在某些情况下没有。 语言设计是妥协; 你不能赢得他们所有。 我不确定我会做出什么决定......

尽管您认为 long 在内部使用的位比浮点多是正确的,但 Java 语言的工作路径越来越宽:

byte -> short -> int -> long -> float -> double

要从左到右转换(扩大转换),不需要强制转换(这就是为什么允许长时间浮动)。 要从右向左转换(缩小转换),需要显式转换。

我在某处听到了这个。 Float 可以按我们所写的指数形式存储。 '23500000000' 存储为 '2.35e10' 。因此,float 有空间占据 long 的值范围。 以指数形式存储也是精度损失的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM