Печать очень больших чисел с плавающей запятой
#include <stdio.h>
#include <float.h>
int main()
{
printf("%f\n", FLT_MAX);
}
Выход из GNU:
340282346638528859811704183484516925440.000000
Выход из Visual Studio:
340282346638528860000000000000000000000.000000
Соответствуют ли стандарты C и С++ для обоих результатов? Или они задают конкретный результат?
Обратите внимание, что FLT_MAX = 2^128-2^104 = 340282346638528859811704183484516925440
.
Ответы
Ответ 1
Я думаю, что соответствующая часть стандарта C99 - это "Рекомендуемая практика" из 7.19.6.1 с .13:
Для преобразований e
, e
, f
, f
, g
и g
, если число значащих десятичных цифр не больше DECIMAL_DIG
, то результат должен быть правильно округлен. Если количество Значительные десятичные цифры больше, чем DECIMAL_DIG
, но исходное значение точно представляемый с цифрами DECIMAL_DIG
, тогда результат должен быть точным представление с конечными нулями. В противном случае значение источника ограничено двумя смежные десятичные строки L < U, причем оба имеют DECIMAL_DIG
значащие цифры; Значение результирующей десятичной строки D должно удовлетворять L <= D <= U, с дополнительным условием, что ошибка должна иметь правильный знак для текущего направления округления.
У меня сложилось впечатление, что это допускает некоторую свободу действий в том, что можно напечатать в этом случае; поэтому я пришел к выводу, что VS и GCC совместимы здесь.
Ответ 2
Оба разрешены стандартом C (С++ просто поддерживает стандарт C)
Из черновик версии в разделе 5.2.4.2.2 часть 10
Значения, приведенные в следующем списке, должны быть заменены постоянными выражениями с значения, определенные при реализации, которые больше или равны показанным:
- максимальное представимое конечное число точек флексирования, (1 - b -p) b emax
FLT_MAX 1E+37
и визуальный С++ 2012 имеет
#define FLT_MAX 3.402823466e+38F /* max value */
Ответ 3
Сам код ошибочен, где он использует %f
для значения, большего, чем значение, содержащееся в float
или double
. Поступая таким образом, вы просите увидеть "за занавесом" относительно бессмысленных битов защиты или другого шума с плавающей точкой, генерируемого при преобразовании в десятичный.
Ясно, что вы не должны ожидать какой-либо согласованности в металлических документах, созданных после создания двигателя в Honda против Toyota. Никогда не думайте о каком-либо разумном ожидании такой последовательности.
Правильный способ отображения таких чисел - использование одного из "научных" форматов, таких как %g
при условии, что точность не переопределена. В реализациях IEEE-754 7 десятичных цифр значимы для float
, 15-16 для double
, около 19 для long double
и 34 для __float128
. Итак, для примера, который вы указали, %.15g
будет правильным, если предположить, что он реализован в IEEE-754.