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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1293819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 07:54:01  来源:igfitidea点击:

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

javacasting

提问by Eric Wilson

Every time I think I understand about casting and conversions, I find another strange behavior.

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

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

Given that a longhas greater bit-depth than a float, I would expect that an explicit cast would be required in order for this to compile. And not surprisingly, we see that we have lost precision in the result.

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

Why is a cast not required here?

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

采纳答案by Jon Skeet

The same question could be asked of longto double- both conversions may lose information.

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

Section 5.1.2 of the Java Language Specificationsays:

Java 语言规范的第 5.1.2 节说:

Widening primitive conversions do not lose information about the overall magnitude of a numeric value. Indeed, conversions widening from an integral type to another integral type do not lose any information at all; the numeric value is preserved exactly. Conversions widening from float to double in strictfp expressions also preserve the numeric value exactly; however, such conversions that are not strictfp may lose information about the overall magnitude of the converted value.

Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision-that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (§4.2.4).

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

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

In other words even though you may lose information, you know that the value will still be in the overall range of the target type.

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

The choice could certainly have been made to require all implicit conversions to lose no information at all - so intand longto floatwould have been explicit and longto doublewould have been explicit. (intto doubleis okay; a doublehas enough precision to accurately represent all intvalues.)

当然可以选择要求所有隐式转换完全不丢失任何信息 - 所以intand longtofloat本来是显式的,longtodouble本来是显式的。(inttodouble没问题; adouble有足够的精度来准确表示所有int值。)

In some cases that would have been useful - in some cases not. Language design is about compromise; you can't win 'em all. I'm not sure what decision I'd have made...

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

回答by cletus

The Java Language Specification, Chapter 5: Conversion and Promotionaddresses this issue:

Java语言规范,第5章:推广转化解决此问题:

5.1.2 Widening Primitive Conversion

The following 19 specific conversions on primitive types are called the widening primitive conversions:

  • byte to short, int, long, float, or double
  • short to int, long, float, or double
  • char to int, long, float, or double
  • int to long, float, or double
  • long to float or double
  • float to double

Widening primitive conversions do not lose information about the overall magnitude of a numeric value.

...

Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision-that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value

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 可能会导致精度损失——也就是说,结果可能会丢失值的一些最低有效位。在这种情况下,生成的浮点值将是整数值的正确舍入版本

To put it another way, the JLS distinguishes between a loss of magnitudeand a loss of precision.

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

intto bytefor example is a (potential) loss of magnitude because you can't store 500 in a byte.

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

longto floatis a potential loss of precision but not magnitude because the value range for floats is larger than that for longs.

longtofloat是精度的潜在损失,但不是幅度,因为浮点数的值范围大于长数的值范围。

So the rule is:

所以规则是:

  • Loss of magnitude:explicit cast required;
  • Loss of precision:no cast required.
  • 量级损失:需要显式转换;
  • 精度损失:不需要铸造。

Subtle? Sure. But I hope that clears that up.

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

回答by Peter

Though you're correct that a long uses more bits internally than a float, the java language works on a widening path:

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

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

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

To convert from left to right (a widening conversion), there is no cast necessary (which is why long to float is allowed). To convert right to left (a narrowing conversion) an explicit cast is necessary.

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

回答by george

Somewhere I heard this. Float can store in exponential form as is we write it. '23500000000' is stored as '2.35e10' .So, float has space to occupy the range of values of long. Storing in exponential form is also the reason for precision loss.

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