При бросании поплавков в целые числа переполнение вызывает неопределенное поведение. Из спецификации C99, раздел 6.3.1.4 Реальных плавучего и целого числа:
Если конечное значение действительного типа с плавающим преобразуются в тип целого числа, отличный _Bool
, дробная часть отбрасывается (то есть, значение усекается к нулю). Если значение интегральной части не может быть представлено целым типом, поведение не определено.
Вы должны проверить диапазон вручную, но не используйте код, как:
// DON'T use code like this!
if (my_double > INT_MAX || my_double < INT_MIN)
printf("Overflow!");
INT_MAX
целая константа, которая не может иметь точное представление с плавающей точкой. По сравнению с поплавком он может быть округлен до ближайшего более высокого или ближайшего нижнего представляемого значения с плавающей запятой (это определяется реализацией). С 64-битными целыми числами, например, INT_MAX
- 2^63 - 1
, который обычно округляется до 2^63
, поэтому проверка по существу становится my_double > INT_MAX + 1
. Это не будет обнаруживать переполнение, если my_double
равно 2^63
.
Например с GCC 4.9.1 на Linux, в следующей программе
#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\n", d, i, d > i ? "true" : "false");
return 0;
}
печатает
9223372036854775808.000000 > 9223372036854775807 is false
Это трудно получить это право, если вы не знаете, пределы и внутреннее представление целые и двойные типы заранее. Но если вы конвертировать из double
в int64_t
, например, вы можете использовать константы с плавающей точкой, которые являются точные двойники (при условии дополнения до двух и IEEE удваивается):
if (!(my_double >= -9223372036854775808.0 // -2^63
&& my_double < 9223372036854775808.0) // 2^63
) {
// Handle overflow.
}
Конструкция !(A && B)
также обрабатывает правильно пренебрежимо малых.Портативная, безопасная, но slighty неточной версии для int
с является:
if (!(my_double > INT_MIN && my_double < INT_MAX)) {
// Handle overflow.
}
Это заблуждается на стороне предостережения и ложно отклонять значения, которые равны или INT_MIN
INT_MAX
. Но для большинства приложений это должно быть хорошо.
[Приведение минимального 32-битного целого числа (-2147483648) в float дает положительное число (2147483648.0)] (http://stackoverflow.com/q/11536389/995714) –