Странное поведение при преобразовании строк C в / из двойников
У меня возникли проблемы с пониманием правил Си для определения точности, которую следует учитывать при печати с удвоением или при преобразовании строк в удвоение. Следующая программа должна проиллюстрировать мою точку зрения:
#include <errno.h>
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
double x, y;
const char *s = "1e-310";
/* Should print zero */
x = DBL_MIN/100.;
printf("DBL_MIN = %e, x = %e\n", DBL_MIN, x);
/* Trying to read in floating point number smaller than DBL_MIN gives an error */
y = strtod(s, NULL);
if(errno != 0)
printf(" Error converting '%s': %s\n", s, strerror(errno));
printf("y = %e\n", y);
return 0;
}
Вывод, который я получаю при компиляции и запуске этой программы (на Core 2 Duo с gcc 4.5.2):
DBL_MIN = 2.225074e-308, x = 2.225074e-310
Error converting '1e-310': Numerical result out of range
y = 1.000000e-310
Мои вопросы:
- Почему x печатается как ненулевое число? Я знаю, что компиляторы иногда продвигают значения типа double для типов с более высокой точностью, но не должен ли printf рассматривать x как 64-битный тип double?
- Если библиотека C тайно использует числа с плавающей запятой с повышенной точностью, почему strtod устанавливает errno при попытке преобразовать эти небольшие числа? И почему это все равно дает правильный результат?
- Является ли это поведение просто ошибкой, результатом моего конкретного оборудования и среды разработки? (К сожалению, в настоящее время я не могу тестировать на других платформах.)
Спасибо за любую помощь, которую вы можете оказать. Я постараюсь прояснить проблему, когда получу обратную связь.
2 ответа
Из-за наличия денормальных чисел в стандарте IEEE-754.
DBL_MIN
это наименьшее нормированное значение.Поскольку стандарт так говорит (C99 7.20.1.3):
Если результат недооценен (7.12.1), функции возвращают значение, величина которого не больше, чем наименьшее нормализованное положительное число в типе возврата; получает ли errno значение ERANGE, определяется реализацией.
Возврат "правильного" значения (т. Е. 1e-310) подчиняется вышеуказанному ограничению.
Так что не ошибка. Это технически зависит от платформы, потому что стандарт (ы) C не предъявляет никаких требований к существованию или поведению ненормальных чисел (AFAIK).
Вот что говорит стандарт для strtod
недолив (C99, 7.20.1.3p10)
"Если результат потерян (7.12.1), функции возвращают значение, величина которого не превышает наименьшего нормализованного положительного числа в типе возврата; независимо от того, получает ли errno значение ERANGE, определяется реализацией".
относительно ERANGE
на strtod
underflow, вот что говорит glibc
"Когда происходит потеря значения, возникает исключение потери значения, и возвращается ноль (с соответствующей подписью). Errno может быть установлено в ERANGE, но это не гарантируется".
http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Math-Error-Reporting.html
(Обратите внимание, что эта страница явно связана с glibc strtod
страница "Разбор поплавков": http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Parsing-of-Floats.html