在 C 中将双精度数转换为整数时处理溢出

新手上路,请多包涵

今天,我注意到当我将大于最大可能整数的双精度数转换为整数时,我得到 -2147483648。同样,当我转换一个小于最小可能整数的双精度时,我也会得到 -2147483648。

是否为所有平台定义了这种行为?

检测这种下溢/溢出的最佳方法是什么?在强制转换之前放置 min 和 max int 的 if 语句是最佳解决方案吗?

原文由 Liliana Larson 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 441
1 个回答

将浮点数转换为整数时,溢出会导致未定义的行为。来自 C99 规范,第 6.3.1.4 节 Real floating and integer

当实浮点类型的有限值转换为除 _Bool 之外的整数类型时,小数部分被丢弃(即,该值被截断为零)。如果整数部分的值不能用整数类型表示,则行为未定义。

您必须手动检查范围,但 不要使用以下代码

 // DON'T use code like this!
if (my_double > INT_MAX || my_double < INT_MIN)
    printf("Overflow!");

INT_MAX 是一个 可能没有精确浮点表示 的整数常量。与浮点数进行比较时,它可能会舍入到最接近的更高或最接近的可表示浮点值(这是实现定义的)。 With 64-bit integers, for example, INT_MAX is 2^63 - 1 which will typically be rounded to 2^63 , so the check essentially becomes my_double > INT_MAX + 1 .如果 my_double 等于 2^63 ,则不会检测到溢出。

例如在 Linux 上使用 gcc 4.9.1,以下程序

#include <math.h>
#include <stdint.h>
#include <stdio.h>

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_MININT_MAX 的值。但是对于大多数应用程序来说,这应该没问题。

原文由 nwellnhof 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题