我在向Int32.MaxValue
进行往返System.Single
时遇到意外结果:
Int32 i = Int32.MaxValue;
Single s = i;
Int32 c = (Int32)s;
Debug.WriteLine(i); // 2147483647
Debug.WriteLine(c); // -2147483648
我意识到它必须溢出,因为Single
在有效位数中没有足够的位来保存Int32
值,并且它会向上舍入。当我在IL中将conv.r4
更改为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
我对JVM知之甚少,但我想知道它是如何做到的。这似乎不那么令人惊讶,但是在四舍五入到2.14748365E9后它如何保留额外的数字?它是否保留某种内部表示,然后在转回int
时替换它?或者只是向下舍入到Integer.MAX_VALUE
以避免溢出?
答案 0 :(得分:3)
这种情况由Java语言规范的§5.1.3显式处理:
a的缩小转换 浮点数到一个整数 T型需要两个步骤:
- 在第一步中,转换浮点数 要么长,要么长,要么 一个int,如果T是byte,short,char或 int,如下:
醇>
- 如果浮点数是NaN(§4.2.3),则结果为 转换的第一步是int 或者长0。
- 否则,如果浮点数不是 无穷大,浮点值是 四舍五入为整数值V, 使用IEEE 754向零舍入 圆向零模式(§4.2.3)。然后 有两种情况:
- 如果T很长,则此整数值可以表示为a 很久,然后是第一个结果 step是长值V。
- 否则,如果此整数值可以表示为int, 然后第一步的结果是 int值V.
- 否则,以下两种情况之一必须为真:
- 该值必须太小(大幅度的负值) 或负无穷大),结果 第一步是最小的 int或类型的可表示值 长。
- 该值必须太大(大幅度的正值) 或正无穷大),结果 第一步是最大的 int或类型的可表示值 长。强>