为什么Java隐式地(没有强制转换)将`long`转换为`float`?
每当我想到我对投射和转换的理解时,就会发现另一种奇怪的行为。
long l = 123456789L; float f = l; System.out.println(f); // outputs 1.23456792E8
考虑到一个long
比float
更深一点,我会期待一个明确的强制转换才能被编译。 并不奇怪,我们看到我们已经失去了结果的精确度。
为什么这里不需要演员?
同样的问题可能会被要求double
– 这两个转换可能会失去信息。
Java语言规范的第5.1.2节说:
拓宽原始转换不会丢失有关数值整体大小的信息。 事实上,从整体types向另一个整体types的转换不会丢失任何信息; 数值被完全保存。 在strictfpexpression式中,从float扩展到double的转换也会完全保留数值; 然而,这种非strictfp的转换可能会丢失有关转换价值总体幅度的信息。
将int或long值转换为float值,或将long值转换为double值可能会导致精度损失 – 也就是说,结果可能会丢失值的某些最低有效位。 在这种情况下,使用IEEE 754 round-to-nearest模式(§4.2.4),得到的浮点值将是整数值的正确舍入版本。
换句话说,即使您可能会丢失信息,但您知道该值仍将处于目标types的整个范围内。
可以肯定的是,要求所有隐式转换完全不会丢失任何信息,所以int
和long
的float
是明确的,而long
的double
是明确的。 ( int
double
是好的; double
有足够的精度来准确地表示所有的int
值。)
在某些情况下,这将是有用的 – 在某些情况下不是。 语言devise是妥协; 你们赢不了所有人。 我不知道我做了什么决定
Java语言规范第5章:转换和促销解决了这个问题:
5.1.2拓宽原始转换
原始types的以下19个特定转换称为扩展原始转换:
- byte,short,int,long,float或double
- 简称int,long,float或double
- char为int,long,float或double
- int long,float或double
- 长时间浮动或翻倍
- 浮动到一倍
拓宽原始转换不会丢失有关数值整体大小的信息。
…
将int或long值转换为float值,或将long值转换为double值可能会导致精度损失 – 也就是说,结果可能会丢失值的某些最低有效位。 在这种情况下,生成的浮点值将是整数值的正确舍入版本
换句话说,JLS区分了数量的损失和精确度的损失。
int
为byte
例如是(潜在的)幅度的损失,因为你不能存储在一个byte
500。
long
float
是一个潜在的精度损失,但不是数量级,因为漂浮物的数值范围大于long
。
所以规则是:
- 数量的损失:需要明确的演员;
- 精确度损失:不需要投射。
微妙? 当然。 但是我希望能够解决这个问题。
虽然长时间使用浮点数比内部使用更多的位是正确的,但是Java语言的工作原理却是一个拓宽的道路:
byte – > short – > int – > long – > float – > double
为了从左向右转换(扩展转换),不需要强制转换(这就是允许长浮动的原因)。 要从右向左转换(缩小转换),需要显式转换。
我听说过这个地方 正如我们所写,浮点数可以以指数forms存储。 “23500000000”被存储为“2.35e10”。因此,float具有占用long值的范围的空间。 以指数forms存储也是精度损失的原因。