„pływająca” a „podwójna” precyzja


155

Kod

float x  = 3.141592653589793238;
double z = 3.141592653589793238;
printf("x=%f\n", x);
printf("z=%f\n", z);
printf("x=%20.18f\n", x);
printf("z=%20.18f\n", z);

da ci wyjście

x=3.141593
z=3.141593
x=3.141592741012573242
z=3.141592653589793116

gdzie w trzecim wierszu danych wyjściowych 741012573242jest śmieci, a w czwartym wierszu 116. Czy gra podwójna zawsze ma 16 cyfr znaczących, podczas gdy zmienna zawsze ma 7 cyfr znaczących? Dlaczego pary nie mają 14 cyfr znaczących?

Odpowiedzi:


146

Liczby zmiennoprzecinkowe w języku C używają kodowania IEEE 754 .

Ten typ kodowania używa znaku, znaczenia i wykładnika.

Z powodu tego kodowania wiele liczb będzie miało niewielkie zmiany, aby umożliwić ich przechowywanie.

Ponadto liczba cyfr znaczących może się nieznacznie zmienić, ponieważ jest to reprezentacja binarna, a nie dziesiętna.

Pojedyncza precyzja (liczba zmiennoprzecinkowa) daje 23 bity znaczenia, 8 bitów wykładnika i 1 bit znaku.

Podwójna precyzja (podwójna) daje 52 bity istotności, 11 bitów wykładnika i 1 bit znaku.


4
C99 tak, wcześniej zależało to od kompilatora.
Alan Geleynse

21
-1 To stwierdzenie jest rażąco fałszywe: „Z powodu tego kodowania nigdy nie można zagwarantować, że nie nastąpi zmiana wartości”.
R .. GitHub STOP POMAGANIE LODOM

16
@Alan: C99 nie wymaga zmiennoprzecinkowego IEEE; po prostu to poleca.
R .. GitHub STOP POMAGANIE LODOM

4
@Alan: R .. ma rację; Załącznik F (który określa wiązania IEEE-754) jest normatywny, ale obowiązuje tylko wtedy, gdy implementacja definiuje __STDC_IEC_559__. Implementacja, która nie definiuje tego makra, może nie być zgodna z IEEE-754.
Stephen Canon

12
@Alan: poniżej standardu IEEE 754, to łatwo zagwarantować, że nie ma żadnych zmian w wartościach 0.5, 0.046875albo 0.376739501953125porównaniu ich reprezentacje po przecinku. (Są to wszystkie wymierne diadyczne z licznikiem pasującym do mantysy i logarytmem o podstawie-2 z mianownika pasującego do wykładnika.)
R .. GitHub STOP HELPING ICE

42

Czy gra podwójna zawsze ma 16 cyfr znaczących, podczas gdy zmienna zawsze ma 7 cyfr znaczących?

Nie. Podwójne zawsze mają 53 znaczące bity, a zmiennoprzecinkowe zawsze 24 znaczące bity (z wyjątkiem denormali, nieskończoności i wartości NaN, ale są to tematy dla innego pytania). Są to formaty binarne i można jasno mówić tylko o precyzji ich reprezentacji w postaci cyfr binarnych (bitów).

Jest to analogiczne do pytania, ile cyfr może być przechowywanych w binarnej liczbie całkowitej: 32-bitowa liczba całkowita bez znaku może przechowywać liczby całkowite do 32 bitów, które nie są dokładnie odwzorowane na dowolną liczbę cyfr dziesiętnych: wszystkie liczby całkowite do Można zapisać 9 cyfr dziesiętnych, ale można również zapisać wiele liczb 10-cyfrowych.

Dlaczego pary nie mają 14 cyfr znaczących?

Kodowanie podwójnej liczby wykorzystuje 64 bity (1 bit na znak, 11 bitów na wykładnik, 52 jawne znaczące bity i jeden niejawny bit), co stanowi dwukrotność liczby bitów użytych do przedstawienia liczby zmiennoprzecinkowej (32 bity).


15

float: 23 bity znacznika, 8 bitów wykładnika i 1 bit znaku.

double: 52 bity istotności, 11 bitów wykładnika i 1 bit znaku.


11

Zwykle opiera się na liczbach znaczących zarówno wykładnika, jak i istotności o podstawie 2, a nie o podstawie 10. Z tego, co mogę powiedzieć w standardzie C99, nie ma jednak określonej precyzji dla liczb zmiennoprzecinkowych i podwójnych (poza faktem, że 1 i 1 + 1E-5/ 1 + 1E-7są rozróżnialne [ floatidouble odpowiednio]). Jednak liczba cyfr znaczących pozostaje w gestii implementującego (a także z jakiej bazy korzysta wewnętrznie, więc innymi słowy, implementacja może zdecydować się na jej wykonanie w oparciu o 18 cyfr dokładności w bazie 3). [1]

Jeśli chcesz znać te wartości, stałe FLT_RADIXi FLT_MANT_DIG(i DBL_MANT_DIG/ LDBL_MANT_DIG) są zdefiniowane w float.h.

Powodem, dla którego nazywa się a, doublejest to, że liczba bajtów użytych do jego przechowywania jest dwa razy większa niż liczba zmiennoprzecinkowa (ale obejmuje to zarówno wykładnik, jak i mantynę). Standard IEEE 754 (używany przez większość kompilatorów) przydziela relatywnie więcej bitów dla istotności niż wykładnik (23 do 9 w floatporównaniu z 52 do 12 w przypadku double), dlatego precyzja jest ponad dwukrotnie większa.

1: Sekcja 5.2.4.2.2 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf )


Literówka? C89 wymaga co najwyżej epsilon 1E-9for double, not 1E-7.
Rufflewind


4

Nie jest to dokładnie podwójna precyzja ze względu na sposób działania IEEE 754 i ponieważ binarny nie przekłada się dobrze na dziesiętne. Jeśli jesteś zainteresowany, spójrz na standard.


4

float oznacza liczbę zmiennoprzecinkową. W C typ danych zmiennoprzecinkowych jest używany w tych przypadkach, w których dokładność całkowitej liczby cyfr wynosi 7, np. Wartość 12.3546987 nie może zostać zapisana jako liczba zmiennoprzecinkowa, ponieważ ma w sumie 9 cyfr. Wyjście zostanie pokazane jako 12.354699, tj. Pierwsze 7 cyfr zostanie pokazanych zgodnie z wprowadzonymi danymi, a 8 cyfra zostanie zaokrąglona. Typ zmiennoprzecinkowy może przedstawiać wartości w zakresie od około 1,5 x 10 ^ (- 45) do 3,4 x 10 ^ (38). Pod względem alokacji pamięci, zmiennoprzecinkowy typ danych o pojedynczej precyzji, 32-bitowy zmiennoprzecinkowy.

W przeciwieństwie do liczby zmiennoprzecinkowej, double ma dokładność od 15 do 16 cyfr. Zakres double wynosi od 5,0 × 10 ^ (- 345) do 1,7 × 10 ^ (308). Pod względem alokacji bajtów, double to 64-bitowe dane zmiennoprzecinkowe rodzaj.

Problem pojawia się w jego użyciu. Float lub double nie wpływa na printf, ale w przypadku scanf należy użyć odpowiedniego typu danych w zależności od liczby całkowitej. cyfr w pływającym nr. to ma być odczytane z wejścia.

Dlatego double jest preferowany zamiast float, aby uzyskać większą dokładność danych.

Mam nadzieję że to pomoże.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.