tags:

views:

490

answers:

7

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?

A: 

Hi There,

I am not sure about this but I think it may be possible to "turn on" floating point exceptions for under/overflow...take a look at this Dealing with Floating-point Exceptions in MSVC7\8 so you might have an alternative to if/else checks.

SDX2000
A: 

I can't tell you for certain whether it is defined for all platforms, but that is pretty much what's happened on every platform I've used. Except, in my experience, it rolls. That is, if the value of the double is INT_MAX + 2, then when the result of the cast ends up being INT_MIN + 2.

As for the best way to handle it, I'm really not sure. I've run up against the issue myself, and have yet to find an elegant way to deal with it. I'm sure someone will respond that can help us both there.

Jeff Barger
+13  A: 

limits.h has constants for max and min possible values for integer data types, you can check your double variable before casting, like

if (my_double > INT_MAX || my_double < INT_MIN)
    printf("Overflow!");
else
    my_int = (int)my_double;
qrdl
+4  A: 

A portable way for C++ is to use the SafeInt class:

http://www.codeplex.com/SafeInt

The implementation will allow for normal addition/subtract/etc on a C++ number type including casts. It will throw an exception whenever and overflow scenario is detected.

SafeInt<int> s1 = INT_MAX;
SafeInt<int> s2 = 42;
SafeInt<int> s3 = s1 + s2;  // throws

I highly advise using this class in any place where overflow is an important scenario. It makes it very difficult to avoid silently overflowing. In cases where there is a recovery scenario for an overflow, simply catch the SafeIntException and recover as appropriate.

SafeInt now works on GCC as well as Visual Studio

JaredPar
pretty cool. is there much overhead though?
SoloBold
A: 

Is this because you're converting 8 bytes to 4 bytes and the magnitude bit ends up being 1 in either case?

GregD
+1  A: 

Another option is to use boost::numeric_cast which allows for arbitrary conversion between numerical types. It detects loss of range when a numeric type is converted, and throws an exception if the range cannot be preserved.

The website referenced above also provides a small example which should give a quick overview on how this template can be used.

Of course, this isn't plain C anymore ;-)

fhe
+7  A: 

To answer your question: The behaviour when you cast out of range floats is undefined or implementation specific.

Speaking from experience: I've worked on a MIPS64 system that didn't implemented these kind of casts at all. Instead of doing something deterministic the CPU threw a CPU exception. The exception handler that ought to emulate the cast returned without doing anything to the result.

I've ended up with random integers. Guess how long it took to trace back a bug to this cause. :-)

You'll better do the range check yourself if you aren't sure that the number can't get out of the valid range.

Nils Pipenbrinck