今天,我注意到当我将一个大于最大可能整数的double转换为整数时,我得到-2147483648.类似地,当我转换一个小于最小可能整数的double时,我也得到-2147483648.
是否为所有平台定义了此行为?
在/溢出下检测此问题的最佳方法是什么?在演示之前将if语句放入min和max int是最佳解决方案吗?
将浮点数转换为整数时,溢出会导致未定义的行为.从C99规范,第6.3.1.4节实数浮动和整数:
当实数浮动类型的有限值被转换为除了以外的整数类型时
_Bool
,小数部分被丢弃(即,该值被截断为零).如果整数部分的值不能用整数类型表示,则行为是未定义的.
您必须手动检查范围,但不要使用如下代码:
// DON'T use code like this! if (my_double > INT_MAX || my_double < INT_MIN) printf("Overflow!");
INT_MAX
是一个整数常量,可能没有精确的浮点表示.与float相比,它可以舍入到最接近的更高或最接近的可表示浮点值(这是实现定义的).与64位整数,例如,INT_MAX
是2^63 - 1
将通常被舍入到2^63
的,所以检查变得基本my_double > INT_MAX + 1
.如果my_double
等于,则不会检测到溢出2^63
.
例如,在Linux上使用gcc 4.9.1,以下程序
#include#include #include int main() { double d = pow(2, 63); int64_t i = INT64_MAX; printf("%f > %lld is %s\n", d, i, d > i ? "true" : "false"); return 0; }
版画
9223372036854775808.000000 > 9223372036854775807 is false
如果您事先不知道整数和双精度的限制和内部表示,那么很难做到这一点.但是,如果你转换double
为int64_t
,例如,你可以使用精确双倍的浮点常数(假设两个补码和IEEE双精度):
if (!(my_double >= -9223372036854775808.0 // -2^63 && my_double < 9223372036854775808.0) // 2^63 ) { // Handle overflow. }
该构造!(A && B)
还正确处理NaN.int
s的便携,安全但略微不准确的版本是:
if (!(my_double > INT_MIN && my_double < INT_MAX)) { // Handle overflow. }
这在谨慎方面是错误的,并且会错误地拒绝等于INT_MIN
或等于的值INT_MAX
.但对于大多数应用程序,这应该没问题.
limits.h
具有整数数据类型的最大和最小可能值的常量,您可以在转换之前检查双变量,例如
if (my_double > nextafter(INT_MAX, 0) || my_double < nextafter(INT_MIN, 0)) printf("Overflow!"); else my_int = (int)my_double;
编辑:nextafter()
将解决nwellnhof提到的问题
回答你的问题:当你抛出范围浮点数时的行为是未定义的或特定于实现的.
从经验谈起:我曾经在MIPS64系统上工作,根本没有实现这些类型的演员表.CPU没有做出确定性的事情,而是抛出了CPU异常.应该模拟转换的异常处理程序,而不对结果做任何事情.
我最终得到了随机整数.猜猜追溯一个错误到这个原因需要多长时间.:-)
如果您不确定该数字是否超出有效范围,您最好自己进行范围检查.