问题描述
今天,我注意到当我将一个大于最大可能整数的 double 转换为整数时,我得到 -2147483648.同样,当我投射一个小于最小可能整数的双精度时,我也会得到 -2147483648.
Today, I noticed that when I cast a double that is greater than the maximum possible integer to an integer, I get -2147483648. Similarly, when I cast a double that is less than the minimum possible integer, I also get -2147483648.
此行为是否适用于所有平台?
检测此下溢/溢出的最佳方法是什么?将 min 和 max int 的 if 语句放在强制转换之前是最佳解决方案吗?
Is this behavior defined for all platforms?
What is the best way to detect this under/overflow? Is putting if statements for min and max int before the cast the best solution?
推荐答案
将浮点数转换为整数时,溢出会导致未定义的行为.来自 C99 规范的 6.3.1.4 实浮点和整数部分:
When casting floats to integers, overflow causes undefined behavior. From the C99 spec, section 6.3.1.4 Real floating and integer:
当浮点实数的有限值被转换为_Bool
以外的整数类型时,小数部分被丢弃(即,该值被截断为零).如果整数部分的值不能用整数类型表示,则行为未定义.
When a finite value of real floating type is converted to an integer type other than
_Bool
, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.
您必须手动检查范围,但不要使用像这样的代码:
You have to check the range manually, but don't use code like:
// DON'T use code like this!
if (my_double > INT_MAX || my_double < INT_MIN)
printf("Overflow!");
INT_MAX
是一个整数常量,可能没有精确的浮点表示.与浮点数进行比较时,它可能会四舍五入到最接近的较高或最接近较低的可表示浮点值(这是实现定义的).例如,对于 64 位整数,INT_MAX
是 2^63 - 1
,通常会四舍五入为 2^63
,因此检查本质上变成了 my_double >INT_MAX + 1
.如果 my_double
等于 2^63
,则不会检测到溢出.
INT_MAX
is an integer constant that may not have an exact floating-point representation. When comparing to a float, it may be rounded to the nearest higher or nearest lower representable floating point value (this is implementation-defined). 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
. This won't detect an overflow if my_double
equals 2^63
.
例如在 Linux 上使用 gcc 4.9.1,以下程序
For example with gcc 4.9.1 on Linux, the following program
#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
", d, i, d > i ? "true" : "false");
return 0;
}
印刷品
9223372036854775808.000000 > 9223372036854775807 is false
如果您事先不知道 integer 和 double 类型的限制和内部表示,就很难做到这一点.但是,如果您从 double
转换为 int64_t
,例如,您可以使用精确双精度的浮点常量(假设二进制补码和 IEEE 双精度):
It's hard to get this right if you don't know the limits and internal representation of the integer and double types beforehand. But if you convert from double
to int64_t
, for example, you can use floating point constants that are exact doubles (assuming two's complement and IEEE doubles):
if (!(my_double >= -9223372036854775808.0 // -2^63
&& my_double < 9223372036854775808.0) // 2^63
) {
// Handle overflow.
}
结构 !(A && B)
也可以正确处理 NaN.int
s 的便携、安全但稍微不准确的版本是:
The construct !(A && B)
also handles NaNs correctly. A portable, safe, but slighty inaccurate version for int
s is:
if (!(my_double > INT_MIN && my_double < INT_MAX)) {
// Handle overflow.
}
这在谨慎方面是错误的,并且会错误地拒绝等于 INT_MIN
或 INT_MAX
的值.但对于大多数应用程序来说,这应该没问题.
This errs on the side of caution and will falsely reject values that equal INT_MIN
or INT_MAX
. But for most applications, this should be fine.
这篇关于在 C 中将双精度转换为整数时处理溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!