Почему% f печатает большие значения, когда константы с плавающей точкой передаются вместо переменных?

9

В данной программе, почему я получил разные результаты для каждого из printfs?

#include <stdio.h>
int main()
{
    float c = 4.4e10;
    printf("%f\n", c);
    printf("%f\n", 4.4e10);
    return 0;
}

И это показывает следующий вывод:

44000002048.000000
44000000000.000000
user10056563
источник
4
Ответы до сих пор объясняют, что 4.4e10это doubleконстанта, которая конвертируется floatв инициализацию, cно сохраняется doubleпри передаче printf. Однако вам также может быть интересно узнать, что добавление fсуффикса делает его floatконстантой: при печати 4.4e10fбудет отображаться то же значение, что и при инициализации cв 4.4e10f. Отличие floatконстант от doubleконстант может быть важным для качественной работы с арифметикой с плавающей точкой.
Эрик Постпищил
Этот метод преобразования называется как-нибудь? Я хочу прочитать об этом.
user10056563
Вы хотите знать, когда происходит преобразование из doubleto floatв язык C? Или вы хотите знать, какие значения получаются в результате преобразования, то есть, какие последствия имеет преобразование? Или что-то другое?
Эрик Постпишил
Я не подвергаю сомнению ни ответы здесь, ни стандарт, но, когда я был молод и учился, Cмы использовали printf("%f",x)для a floatи printf("%lf",x)для a double. Когда все изменилось? И как можно явно напечатать (одиночный) float- printf("%hf",x)??
Адриан Крот
2
@Adrian %lfв printf - это то же самое, что и %f. floatВ переменном аргументе преобразуются в doubleкомпиляторе, так же , как shortполучает преобразовано в int.
SS Anne

Ответы:

9

A float- это тип, который содержит 32-разрядное число с плавающей запятой, в то время как константа 4.4e10представляет собой a double, который содержит 64-разрядное число с плавающей запятой (т.е. число с плавающей запятой двойной точности)

При назначении 4.4e10на cзначение 4.4e10не может быть представлено точно (ошибка округления в качестве параметра называется мантисса), а наиболее возможное значение (44000002048) сохраняется. Когда он передается printf, он переводится обратно double, включая ошибку округления.

Во втором случае значение представляет собой doubleцелое время без сужения и расширения, и это тот случай, когда a doubleможет точно представлять значение.

Если это нежелательное поведение, вы можете объявить его cкак doubleболее точный (но учтите, что в конечном итоге вы все равно достигнете пределов точности).

нФ
источник
3

Вы фактически печатаете значения двух разных типов здесь.

В первом случае вы присваиваете значение переменной типа float. Точность a floatсоставляет примерно 6 или 7 десятичных цифр, поэтому, если значение не может быть представлено точно, вы увидите ближайшее значение, которое может быть представлено этим типом.

Во втором случае вы передаете константу, 4.4e10которая имеет тип double. Этот тип имеет около 16 десятичных цифр точности, и значение находится в этом диапазоне, поэтому печатается точное значение.

dbush
источник
Почему он специально печатает 2048 в конце?
user10056563
@ user10056563 Потому что это самое близкое число к 4.4e10, которое может быть сохранено в 32-разрядном формате с плавающей запятой.
19