При печати значения float
или double
в std::ostream
используется шаблон класса std::num_put<>
(C ++ 03 §22.2.2.2). Он форматирует значение, как если бы оно печаталось с помощью printf
с одним из спецификаторов формата %e
, %E,
%f
, %g
или %G
, в зависимости от флагов потока (Таблица 58).
Аналогично, при вводе значения float
или double
оно считывается как если бы оно было выполнено с помощью функции scanf
со спецификатором формата %g
(§22.2.2.1.2 / 5).
Итак, следующий вопрос: почему scanf
неправильно анализирует 1.#QNAN
. Стандарт C89 не упоминает NaN в своих описаниях функций fprintf
и fscanf
. Это говорит о том, что представление чисел с плавающей запятой не определено, поэтому это поведение не определено.
C99, с другой стороны, определяет здесь поведение. Для fprintf
(C99 §7.19.6.1 / 8):
A double
аргумент, представляющий бесконечность, преобразуется в один из стилей
[-]inf
или [-]infinity
- какой стиль определяется реализацией.
double
аргумент, представляющий NaN, преобразуется в один из стилей
[-]nan
или [-]nan(<em>n-char-sequence</em>)
- какой стиль и значение
any n-char-sequence , определяется реализацией. Спецификатор преобразования F
производит INF
, INFINITY
или NAN
вместо inf
, infinity
или nan
,
соответственно. 243)
fscanf
указывается для анализа числа в соответствии с strtod(3)
(C99 §7.19.6.2 / 12). strtod
разбирает следующим образом (§7.20.1.3 / 3):
Ожидаемая форма предметной последовательности - необязательный знак плюс или минус, затем один из
следующее:
- непустая последовательность десятичных цифр, необязательно содержащая десятичную точку
символ, затем необязательная часть экспоненты, как определено в 6.4.4.2;
- 0x
или 0X
, затем непустая последовательность шестнадцатеричных цифр, необязательно содержащая
символ десятичной точки, затем необязательная двоичная экспоненциальная часть, как определено в 6.4.4.2;
- INF
или INFINITY
, без учета регистра
- NAN
или NAN(<em>n-char-sequence<sub>opt</sub></em>)
, игнорируя регистр в части NAN, где:
n-char-sequence:
digit
nondigit
n-char-sequence digit
n-char-sequence nondigit
Предметная последовательность определяется как самая длинная начальная подпоследовательность входной строки,
начиная с первого символа, не являющегося пробелом, который имеет ожидаемую форму. Предмет
последовательность не содержит символов, если строка ввода не имеет ожидаемой формы.
Итак, после всего этого, в конечном итоге ваша стандартная библиотека C не совместима с C99, поскольку 1.#QNAN
не является допустимым выводом fprintf
в соответствии с вышеприведенным. Но хорошо известно, что среда выполнения Microsoft C не совместима с C99, и, насколько я знаю, она не планирует в ближайшее время стать совместимой. Поскольку C89 не определяет здесь поведение по отношению к NaN, вам не повезло.
Вы можете попробовать переключиться на другой компилятор и среду выполнения C (например, Cygwin + GCC), но это очень большой молоток для такого маленького гвоздя. Если вам действительно нужно такое поведение, я бы порекомендовал написать класс-оболочку для чисел с плавающей точкой, который способен правильно форматировать и анализировать значения NaN.