errno НЕ устанавливается в значение ERANGE после преобразования строки с ОГРОМНЫМ числом в число с двойной плавающей запятой с помощью strtod() в C

#c

Вопрос:

Я озадачен тем, что значение errno не устанавливается ERANGE после strtod() попыток преобразовать строку с огромным действительным числом в число с двойной плавающей запятой.

Вот что происходит, когда я запускаю свой код:

 Enter a real number: 5656565656565652622326352635236523652362356235
You entered 5656565656565652358969982685269310483757793280.000000.
 

Вот мой код:

 #include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int getDouble(char* prompt, double* doubleRealNumber);

int main(void)
{  
    double d;

    getDouble("Enter a real number: ", amp;d);
    printf("You entered %lf.n", d);

    return 0;
}

int getDouble(char* prompt, double* doubleRealNumber)
{
    int const MAXBUFSIZE = 1024;
    char buf[MAXBUFSIZE]; // use 1KiB just to be sure
    int success; // flag for successful conversion
    
    do
    {
        printf("%s", prompt);
        fflush(stdout);
        
        if (!fgets(buf, MAXBUFSIZE, stdin))
        {
            // reading input failed:
            return 1;
        }
        
        // have some input, convert it to integer:
        char *endptr;
        
        errno = 0; // reset error number
    
        *doubleRealNumber = strtod(buf, amp;endptr);
        
        if (errno == ERANGE)
        {
            printf("Sorry, this number is too small or too large.n");
            success = 0;
        }
        else if (endptr == buf)
        {
            // no character was read
            success = 0;
        }
        else if (*endptr amp;amp; *endptr != 'n')
        {
            // *endptr is neither end of string nor newline,
            // so we didn't convert the *whole* input
            success = 0;
        }
        else
        {
            success = 1;
        }
    } while (!success); // repeat until we got a valid real number
    
    return 0;        
}
 

Комментарии:

1. Почему вы ожидаете, что он будет «вне зоны досягаемости»?

2. Это похоже скорее на потерю точности, чем на выход за пределы досягаемости. Не каждое число в динамическом диапазоне (экспоненты) может быть точно представлено (мантиссой).

3. Попробуйте с помощью этого ввода: 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

4. В качестве общего замечания не следует использовать значение errno до проверки того, указывает ли возвращаемое значение функции, что errno оно имеет значение. Вы можете полагаться на неопределенное поведение.

5. Это хороший момент — вы должны только проверить errno HUGE_VAL , возвращается ли он.

Ответ №1:

на самом деле значение errno правильно устанавливается для УДАЛЕНИЯ при вводе очень большого (или очень маленького) числа.

Если ввести действительно большое число, например «100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000», для errno задано значение ERANGE, и выводится следующее: «Извините, это число слишком мало или слишком велико». Таким образом, опубликованный код действителен и работает должным образом.

Причина в том, что входной номер и выходной номер не совпадают в вопросе из-за потери точности, а не из-за диапазона. Не каждое число в динамическом диапазоне (экспоненты) может быть точно представлено (мантиссой).

Большое спасибо Бесполезному и Бармаглоту за то, что указали на это!

Комментарии:

1. Стоит отметить, что установлено ли errno значение ERANGE on underflow, определяется реализацией.