Как бы я напечатал максимально возможный float и double в C?


Для следующего кода,

#include <stdio.h>
#include <limits.h>
#include <float.h>

int main(void) {
    printf("double max = %??n", DBL_MAX);
    printf("double min = %??n", DBL_MIN);
    printf("double epsilon  = %??n", DBL_EPSILON);
    printf("float epsilon  = %??n", FLT_EPSILON);
    printf("float max = %??n", FLT_MAX);
    printf("float min = %??nn", FLT_MIN);
    return 0;
}

Какие спецификаторы я должен был бы использовать вместо ??это для того, чтобы printf отображал различные количества в виде десятичных чисел соответствующего размера?

3 2

3 ответа:

Используйте тот же формат, что и для любых других значений этих типов:

#include <float.h>
#include <stdio.h>
int main(void) {
    printf("FLT_MAX = %g\n", FLT_MAX);
    printf("DBL_MAX = %g\n", DBL_MAX);
    printf("LDBL_MAX = %Lg\n", LDBL_MAX);
}

Аргументы типа float повышаются до double для вариадических функций, таких как printf, поэтому вы используете один и тот же формат для обоих.

%f выводит значение с плавающей запятой, используя десятичную систему счисления без экспоненты, что даст вам очень длинную строку (в основном незначительных) цифр для очень больших значений.

%e заставляет использовать показатель степени.

%g использует либо %f, либо %e, в зависимости от величины печатаемого числа.

В моей системе вышеописанное выводит следующее:

FLT_MAX = 3.40282e+38
DBL_MAX = 1.79769e+308
LDBL_MAX = 1.18973e+4932

Как указывает Эрик Постпишил в комментарии, выше печатаются только приближенные значения. Вы можете напечатать больше цифр, указав точность (количество цифр, которое вам понадобится, зависит от точности типов); например, вы можете заменить %g на %.20g.

Или, если ваша реализация поддерживает его, C99 добавил возможность печати значения с плавающей запятой в шестнадцатеричном формате с необходимой точностью:

printf("FLT_MAX = %a\n", FLT_MAX);
printf("DBL_MAX = %a\n", DBL_MAX);
printf("LDBL_MAX = %La\n", LDBL_MAX);
Но результат не так легко читается человеком, как обычный десятичный формат:
FLT_MAX = 0x1.fffffep+127
DBL_MAX = 0x1.fffffffffffffp+1023
LDBL_MAX = 0xf.fffffffffffffffp+16380

(Примечание: main() - устаревшее определение; вместо этого используйте int main(void).)

Чтобы вывести аппроксимации максимумов с достаточным количеством цифр для представления фактических значений (результатом преобразования напечатанного значения обратно в значение с плавающей запятой должно быть исходное значение), можно использовать:

#include <float.h>
#include <stdio.h>


int main(void)
{
    printf("%.*g\n", DECIMAL_DIG, FLT_MAX);
    printf("%.*g\n", DECIMAL_DIG, DBL_MAX);
    printf("%.*Lg\n", DECIMAL_DIG, LDBL_MAX);
    return 0;
}

В C 2011 Вы можете использовать более конкретный FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, и LDBL_DECIMAL_DIG вместо DECIMAL_DIG.

Чтобы вывести точные значения, вместо аппроксимаций, нужно указать большую точность. (int) (log10(x)+1) цифр должно быть достаточно.

Аппроксимации минимумов и эпсилоны могут быть напечатаны с достаточной точностью таким же образом. Однако вычисление количества цифр, необходимых для точных значений, может оказаться более сложным, чем для максимумов. (Технически это может быть невозможно в экзотических реализациях C. Например, система с плавающей запятой с основанием три будет иметь минимум, не представимый в любом конечном числе десятичных разрядов. Я не знаю о каких-либо таких реализациях в использовании.)

Вы можете использовать последние три отпечатка в моем решении к упражнению 2.1 из языка программирования C

// float or IEEE754 binary32
printf(
    "float: {min: %e, max: %e}, comp: {min: %e, max: %e}\n",
    FLT_MIN, FLT_MAX, pow(2,-126), pow(2,127) * (2 - pow(2,-23))
    );
// double or IEEE754 binary64
printf(
    "double: {min: %e, max: %e}, comp: {min: %e, max: %e}\n",
    DBL_MIN, DBL_MAX, pow(2,-1022), pow(2,1023) * (2 - pow(2,-52))
    );
// long double or IEEE754 binary 128
printf(
    "long double: {min: %Le, max: %Le}, comp: {min: %Le, max: %Le}\n",
    LDBL_MIN, LDBL_MAX, powl(2,-16382), powl(2,16383) * (2 - powl(2,-112))
    );

Очевидно, что максимальные значения вычисляются в соответствии с IEEE 754. Полное решение доступно по ссылке: https://github.com/mat90x/tcpl/blob/master/types_ranges.c