Странное поведение при преобразовании строк C в / из двойников - PullRequest
7 голосов
/ 10 января 2012

У меня возникают проблемы с пониманием правил Си для определения точности при печати удвоений или преобразовании строк в удвоения. Следующая программа должна проиллюстрировать мою точку зрения:

#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

Мои вопросы:

  1. Почему x печатается как ненулевое число? Я знаю, что компиляторы иногда продвигают значения типа double для типов с более высокой точностью для целей вычислений, но не следует ли printf рассматривать x как 64-битный тип double?
  2. Если библиотека C тайно использует числа с плавающей запятой с повышенной точностью, почему strtod устанавливает errno при попытке преобразовать эти небольшие числа? И почему он все равно дает правильный результат?
  3. Является ли это поведение просто ошибкой, результатом моего конкретного аппаратного обеспечения и среды разработки? (К сожалению, на данный момент я не могу тестировать на других платформах.)

Спасибо за любую помощь, которую вы можете оказать. Я постараюсь прояснить проблему, когда получу отзыв.

Ответы [ 2 ]

8 голосов
/ 10 января 2012
  1. Из-за наличия ненормальных чисел в стандарте IEEE-754. DBL_MIN является наименьшим нормализованным значением.

  2. Поскольку в стандарте говорится об этом (C99 7.20.1.3):

    Если результат опустошается (7.12.1), функции возвращают значение, величина которого не больше чем наименьшее нормализованное положительное число в типе возврата; получает ли errno значение ERANGE определяется реализацией.

    Возвращение «правильного» значения (т. Е. 1e-310) подчиняется вышеуказанному ограничению.

  3. Так что не ошибка. Это технически зависит от платформы, потому что стандарт (ы) C не предъявляет никаких требований к существованию или поведению ненормальных чисел (AFAIK).

7 голосов
/ 10 января 2012

Вот что говорит стандарт для strtod недостаточного расхода (C99, 7.20.1.3p10)

"Если результат потерян (7.12.1), функции возвращают значение, величина которого не больше наименьшего нормализованного положительного числа в типе возврата; независимо от того, получает ли ERRGE значение ERANGE, определяется реализацией."

Относительно ERANGE при strtod недополнении, вот что говорит 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

...