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
What is the best way to detect this under/overflow?
Compare the truncated double
to exact limits near INT_MIN,INT_MAX
.
The trick is to exactly convert limits based on INT_MIN,INT_MAX
into double
values. A double
may not exactly represent INT_MAX
as the number of bits in an int
may exceed that floating point's precision. In that case, the conversion of INT_MAX
to double
suffers from rounding. The number after INT_MAX
is a power-of-2 and is certainly representable as a double
. 2.0*(INT_MAX/2 + 1)
generates the whole number one greater than INT_MAX
.
The same applies to INT_MIN
on non-2s-complement machines.
INT_MAX
is always a power-of-2 - 1.
INT_MIN
is always:
-INT_MAX
(not 2's complement) or
-INT_MAX-1
(2's complement)
int double_to_int(double x) {
x = trunc(x);
if (x >= 2.0*(INT_MAX/2 + 1)) Handle_Overflow();
#if -INT_MAX == INT_MIN
if (x <= 2.0*(INT_MIN/2 - 1)) Handle_Underflow();
#else
if (x < INT_MIN) Handle_Underflow();
#endif
return (int) x;
}
To detect NaN and not use trunc()
#define DBL_INT_MAXP1 (2.0*(INT_MAX/2+1))
#define DBL_INT_MINM1 (2.0*(INT_MIN/2-1))
int double_to_int(double x) {
if (x < DBL_INT_MAXP1) {
#if -INT_MAX == INT_MIN
if (x > DBL_INT_MINM1) {
return (int) x;
}
#else
if (ceil(x) >= INT_MIN) {
return (int) x;
}
#endif
Handle_Underflow();
} else if (x > 0) {
Handle_Overflow();
} else {
Handle_NaN();
}
}