Dlaczego% f drukuje duże wartości, gdy zamiast zmiennych zmienne są przekazywane zmiennoprzecinkowe?

9

Dlaczego w danym programie otrzymałem różne wyniki dla każdego z nich printf?

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

I pokazuje następujące dane wyjściowe:

44000002048.000000
44000000000.000000
użytkownik10056563
źródło
4
Dotychczasowe odpowiedzi wyjaśniają, że 4.4e10jest to doublestała, która jest przekształcana floatpodczas inicjalizacji, cale zachowywana jako doubleprzekazana printf. Jednakże, to polubisz też wiedzieć, że dodanie fprzyrostka sprawia mu floatstałej: Druk 4.4e10fpokaże tę samą wartość, która wynika z inicjalizacji cdo 4.4e10f. Odróżnianie floatstałych od doublestałych może być ważne przy wykonywaniu wysokiej jakości pracy z arytmetyką zmiennoprzecinkową.
Eric Postpischil
Czy ta metoda konwersji ma jakąkolwiek nazwę? Chcę o tym poczytać.
user10056563,
Czy chcesz wiedzieć, kiedy konwersja z doublena floatma miejsce w języku C? A może chcesz wiedzieć, jakie wartości wynikają z konwersji, czyli jakie skutki ma konwersja? Albo coś innego?
Eric Postpischil
Mam wątpliwość ani odpowiedzi tutaj ani średnia, ale kiedy byłem młody i uczenia Cużyliśmy printf("%f",x)dla floati printf("%lf",x)dla double. Kiedy coś się zmieniło? A jak by to wyraźnie wydrukować (singiel) float- printf("%hf",x)??
Adrian Mole
2
@Adrian %lfw printf to to samo, co %f. floatArgument A w zmiennej jest konwertowany na doublekompilator, podobnie jak a shortjest konwertowany na an int.
SS Anne

Odpowiedzi:

9

A floatjest typem, który zawiera 32-bitową liczbę zmiennoprzecinkową, podczas gdy stała 4.4e10reprezentuje a double, która zawiera 64-bitową liczbę zmiennoprzecinkową (tj. Liczba zmiennoprzecinkowa podwójnej precyzji)

Po przypisaniu 4.4e10do cwartości 4.4e10nie można dokładnie przedstawić (błąd zaokrąglenia w parametrze zwanym mantysą), a najbliższa możliwa wartość (44000002048) zostaje zapisana. Gdy jest przekazywany printf, jest promowany z powrotem double, łącznie z błędem zaokrąglenia.

W drugim przypadku wartość jest doublecały czas, bez zwężania i poszerzania, i zdarza się, że a doublemoże dokładnie reprezentować wartość.

Jeśli jest to niepożądane zachowanie, możesz zadeklarować c jako doublena nieco większą precyzję (ale pamiętaj, że będziesz nadal hit granice precyzji ostatecznie).

nanofarad
źródło
3

W rzeczywistości drukujesz tutaj wartości dwóch różnych typów.

W pierwszym przypadku przypisujesz wartość zmiennej typu float. Precyzja afloat wynosi około 6 lub 7 cyfr dziesiętnych, więc jeśli nie da się dokładnie przedstawić wartości, zobaczysz najbliższą wartość, którą może reprezentować ten typ.

W drugim przypadku podajesz stałą, 4.4e10która ma typ double. Ten typ ma około 16 cyfr dokładności dziesiętnej, a wartość mieści się w tym zakresie, więc drukowana jest dokładna wartość.

dbush
źródło
Dlaczego konkretnie drukuje 2048 na końcu?
user10056563,
@ user10056563 Ponieważ jest to najbliższa liczba 4.4e10, którą można zapisać w 32-bitowym zmiennoprzecinkowym.
dbush