C#和Java之间溢出语义的差异

本文关键字:语义 溢出 Java 之间 | 更新日期: 2023-09-27 18:28:38

获取以下代码:

const float fValue = 5.5f;
const float globalMin = 0.0f;
const float globalMax = 5.0f;
float vFactor = (float)(2e9 / (globalMax - globalMin));
int iValue = (int)((fValue - globalMin) * vFactor); 

最后一行导致一个值溢出int。在C#中,结果未指定:

  • 6.2.1显式数字转换
  • 对于从浮点或双精度到整型的转换,处理取决于进行转换的溢出检查上下文(§7.6.12):
    • 在未检查的上下文中,转换总是成功的,并按如下方式进行。
      • 如果操作数的值是NaN或无穷大,则转换的结果是目标类型的未指定值
      • 否则,源操作数将向零四舍五入到最接近的整数值。如果这个整数值在目标类型的范围内,那么这个值就是转换的结果
      • 否则,转换的结果是目标类型的未指定值

在java中。。。我不知道,这就是我来这里的原因。我知道如何处理典型的整数溢出(即Integer.MAX_VALUE + 1),但在规范中找不到任何将溢出作为float转换的结果的内容。

在我的测试(Java)中,最后一行的结果是Integer.MAX_VALUE,这告诉我正在发生更多的事情,因为如果值被简单地翻转,我预计它将是-2094967296。看起来Java在溢出时截断为MAX_VALUE

编辑:感谢@Pascal Cuoq指出,将浮点截断为int的SSE2汇编指令在溢出时会产生int_MIN。我将修复C#方面的错误,但我仍然很好奇Java在哪里/是否指定了这种行为。

C#和Java之间溢出语义的差异

数据类型之间的转换在Java语言规范中有很好的定义(请参阅转换和升级部分)。

我相信你的案子属于5.1.3。缩小原始转换,您可以看到:

  • 首先,您的浮点值将使用IEEE 754向零取整模式(此处解释)取整为整数
  • 它将被分配最大或最小的可表示整数值,这取决于该值是太小还是太大