Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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.

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
191 views
Welcome To Ask or Share your Answers For Others

1 Answer

When casting floats to integers, overflow causes undefined behavior. From the C99 spec, section 6.3.1.4 Real floating and integer:

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 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.

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;
}

prints

9223372036854775808.000000 > 9223372036854775807 is false

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.
}

The construct !(A && B)also handles NaNs correctly. A portable, safe, but slighty inaccurate version for ints is:

if (!(my_double > INT_MIN && my_double < INT_MAX)) {
    // Handle overflow.
}

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...