Странное поведение при статическом приведении от большого двойного к целому - PullRequest
9 голосов
/ 09 октября 2011

Вот мой простой код:

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

Вывод:

-2147483648
2147483647
2147483647

Это удивило меня ужасно. Почему положительный двойник иногда приводится к отрицательному int?

Я использую g++: GCC версии 4.4.3 (Ubuntu 4.4.3-4ubuntu5).

Ответы [ 2 ]

5 голосов
/ 09 октября 2011

Приведение double к int, когда int недостаточно велико, чтобы удерживать значение, дает неопределенное поведение .

[n3290: 4.9/1]: Преобразование типа с плавающей запятой может быть преобразовано к значению целочисленного типа. Преобразование усекается; то есть, дробная часть отбрасывается. Поведение не определено, если усеченное значение не может быть представлено в типе назначения.

Это поведение происходит от C:

[C99: 6.3.1.4/1]: Когда конечное значение реального плавающего типа преобразуется в целочисленный тип, отличный от _Bool, дробная часть отбрасывается (то есть значение усекается до нуля). Если значение интегральная часть не может быть представлена ​​целочисленным типом, поведение не определено.

Для вас int явно недостаточно велико.

  • И, в первом случае, для вас именно так и получается, что бит знака установлен.
  • Во втором и третьем случаях, опять же для вас, вероятно, оптимизация может привести к другому поведению.

Но не полагайтесь на или (или, действительно, any ) поведение в этом коде.

5 голосов
/ 09 октября 2011

Из стандарта С (1999):
6.3.1.4. Действительное и целое число
1 Когда конечное значение реального плавающего типа преобразуется в целочисленный тип, отличный от _Bool, дробная часть отбрасывается (то есть значение усекается до нуля). Если значение неотъемлемая часть не может быть представлена ​​целочисленным типом, поведение не определено.

Из стандарта C ++ (2003):
4.9 Плавающие-интегральные преобразования [conv.fpint]
1 R-значение типа с плавающей запятой может быть преобразовано в R-значение целого типа. Преобразование усекается; то есть дробная часть отбрасывается. Поведение не определено, если усеченное значение не может быть представлены в типе назначения. [Примечание: если тип назначения - bool, см. 4.12. ]

Скорее всего, ваш двойник слишком большой, чтобы его можно было правильно преобразовать в int.

...