为什么CLR溢出Int32.MaxValue - > Single - > Int32,而JVM没有?

cod*_*zen 5 floating-point int clr jvm

我遇到了一个意想不到的结果,在往返Int32.MaxValueSystem.Single:

Int32 i = Int32.MaxValue;
Single s = i;
Int32 c = (Int32)s;

Debug.WriteLine(i); // 2147483647
Debug.WriteLine(c); // -2147483648
Run Code Online (Sandbox Code Playgroud)

我意识到它必须溢出,因为有效Single位中没有足够的位来保存Int32值,并且它会向上舍入.当我在IL中更改为conv.r4to conv.r4.ovf时,OverflowExcpetion会抛出一个.很公平...

但是,当我正在研究这个问题时,我在java中编译了这段代码并运行它并得到以下内容:

int i = Integer.MAX_VALUE;
float s = (float)i;
int c = (int)s;

System.out.println(i);  // 2147483647
System.out.println(c);  // 2147483647
Run Code Online (Sandbox Code Playgroud)

我对JVM了解不多,但我想知道它是如何做到的.这似乎不那么令人惊讶,但是在四舍五入到2.14748365E9后它如何保留额外的数字?是否保留了某种内部表示,然后在重新投入时替换它int?或者它只是向下舍入Integer.MAX_VALUE以避免溢出?

Mat*_*hen 3

Java 语言规范的\xc2\xa75.1.3明确处理了这种情况:

\n\n
\n

浮点数到整型 T 的缩小转换需要两个步骤:

\n\n
    \n
  1. 在第一步中,如果 T 是 long,则将浮点数转换为 long;如果 T 是 byte、short、char 或 int,则将浮点数转换为 int,如下所示:\n
      \n
    • 如果浮点数为 NaN (\xc2\xa74.2.3),则第一步转换的结果是 int\n 或 long 0。
    • \n
    • 否则,如果浮点数不是无穷大,则浮点值将四舍五入为整数值 V,使用 IEEE 754 向零舍入模式向零舍入 (xc2 xa74.2.3)。那么\n有两种情况:\n
        \n
      • 如果T是long,并且这个整数值可以表示为long,那么第一步的结果就是long值V。
      • \n
      • 否则,如果这个整数值可以表示为 int,那么第一步的结果就是 int 值 V。
      • \n
    • \n
    • 否则,必须满足以下两种情况之一:\n
        \n
      • 该值必须太小(大幅度的负值或负无穷大),并且第一步的结果是 int 或 long 类型的最小可表示值。
      • \n
      • 该值必须太大(大幅度的正值或正无穷大),并且第一步的结果是 int 或 long 类型的最大可表示值。
      • \n
    • \n
  2. \n
\n
\n