Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behavior when static casting from a big double to an integer

Here 's my simple code:

int main() {
  double d1 = 10000000000.0;
  const double d2 = 10000000000.0;

  cout << static_cast<int>(d1) << endl;
  cout << static_cast<int>(d2) << endl;
  cout << static_cast<int>(10000000000.0) << endl;
}

The output is:

-2147483648
2147483647
2147483647

This surprised me grealy. Why would a positive double sometimes get casted to a negative int?

I'm using g++: GCC version 4.4.3 (Ubuntu 4.4.3-4ubuntu5).

like image 493
Kai Avatar asked Oct 09 '11 12:10

Kai


2 Answers

Casting a double to an int when int isn't big enough to hold the value yields undefined behaviour.

[n3290: 4.9/1]: A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

This behaviour is derived from C:

[C99: 6.3.1.4/1]: 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.

For you, int clearly isn't big enough.

  • And, in the first case, for you this just so happens to result in the sign bit being set.
  • In the second and third cases, again for you, it's probably optimisations that happen to result in different behaviour.

But don't rely on either (or, indeed, any) behaviour in this code.

like image 191
Lightness Races in Orbit Avatar answered Oct 13 '22 02:10

Lightness Races in Orbit


From the C standard (1999):
6.3.1.4 Real floating and integer
1 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.

From the C++ standard (2003):
4.9 Floating-integral conversions [conv.fpint]
1 An rvalue of a floating point type can be converted to an rvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type. [Note: If the destination type is bool, see 4.12. ]

Most likely your double is too big to be converted correctly to int.

like image 31
Alexey Frunze Avatar answered Oct 13 '22 02:10

Alexey Frunze