При преобразовании чисел с плавающей точкой в целые числа переполнение вызывает неопределенное поведение. Из спецификации 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) также правильно обрабатывает NaN. Переносимая, безопасная, но немного неточная версия для ints:
if (!(my_double > INT_MIN && my_double < INT_MAX)) {
// Handle overflow.
}
Это проявляет осторожность и ошибочно отклоняет значения, равные INT_MIN или INT_MAX. Но для большинства приложений это должно быть нормально.
person
nwellnhof
schedule
24.05.2015