strtod underflow, возвращаемое значение!= 0
Вот мой тестовый код:
errno = 0;
d = strtod("1.8011670033376514e-308", NULL);
С этим кодом я получаю d == 1.8011670033376514e-308
а также errno == ERANGE
,
Из strtod(3):
Если правильное значение приведет к переполнению, плюс или минус
HUGE_VAL
(HUGE_VALF
,HUGE_VALL
) возвращается (в зависимости от знака значения) иERANGE
хранится вerrno
, Если правильное значение вызовет недостаточное значение, возвращается ноль иERANGE
хранится вerrno
,
Итак, мне кажется, что либо errno
должно быть ноль (без ошибок) или d
должно быть ноль (недостаточное значение).
Это ошибка, или я что-то упустил? Это происходит для многих разных версий eglibc и gcc.
3 ответа
В §7.22.1.3 strtod()
, strtof()
а также strtold()
функции, стандарт C11 (ISO/IEC 9899:2011) гласит:
Функции возвращают преобразованное значение, если оно есть. Если преобразование не может быть выполнено, возвращается ноль. Если выбрано правильное значение и используется округление по умолчанию (7.12.1), плюс или минус
HUGE_VAL
,HUGE_VALF
, или жеHUGE_VALL
возвращается (в соответствии с типом возвращаемого значения и знаком значения) и значением макросаERANGE
хранится вerrno
, Если результат не достигает цели (7.12.1), функции возвращают значение, величина которого не превышает наименьшего нормализованного положительного числа в типе возврата; будь тоerrno
приобретает ценностьERANGE
определяется реализацией.
В п. 5.2.4.2.2 стандарта также отмечается, что для чисел с плавающей запятой в МЭК 60559 (IEEE 754) существует предел:
DBL_MIN 2.2250738585072014E-308 // decimal constant
Так как 1.8011670033376514e-308 меньше, чем DBL_MIN
, вы получаете не нормальное число, и ERANGE
вполне уместно (но необязательно).
На Mac OS X 10.9.4 с GCC 4.9.1, следующая программа:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *end;
errno = 0;
double d = strtod("1.8011670033376514e-308", &end);
if (errno != 0)
{
int errnum = errno;
printf("%d: %s\n", errnum, strerror(errnum));
}
printf("%24.16e\n", d);
unsigned char *p = (unsigned char *)&d;
const char *pad = "";
for (size_t i = 0; i < sizeof(double); i++)
{
printf("%s0x%.2X", pad, *p++);
pad = " ";
}
putchar('\n');
return 0;
}
производит вывод:
34: Result too large
1.8011670033376514e-308
0x01 0x00 0x00 0x00 0xA8 0xF3 0x0C 0x00
Сообщение об ошибке по иронии судьбы неверно - значение слишком мало - но вы не можете иметь все.
Если strtod()
вернул ненулевое значение (это не +/- HUGE_VAL
) вызов успешно завершен (в соответствии с указанной вами страницей руководства).
Ссылаясь на справочную страницу для errno.h
:
<errno.h>
заголовочный файл определяет целочисленную переменнуюerrno
, который устанавливается системными вызовами и некоторыми библиотечными функциями в случае ошибки, чтобы указать, что пошло не так. Его значение имеет значение только тогда, когда возвращаемое значение вызова указывает на ошибку (т. Е.-1
от большинства системных вызовов;-1
или жеNULL
из большинства библиотечных функций); функция, которая завершается успешно, может быть измененаerrno
,
Таким образом, вы можете только проверить errno
для ошибки, если возвращаемое значение вашей функции фактически возвращает значение, указывающее, что произошла ошибка.
Более полное объяснение errno
(и объяснение его связи с strtod()
) можно найти на другом StackExchange.
Код работает в соответствии со спецификацией Open Group POSIXstrtod()
:
Если правильное значение вызвало бы недостаточное значение, то значение, величина которого не превышает наименьшего нормализованного положительного числа в типе возвращаемого значения, должно быть возвращено и в качестве значения errno установлено значение [ERANGE].
Я бы сказал, что вы видите ошибку в деталях на странице руководства Linux.