Duża różnica.
Jak sama nazwa wskazuje, a double
ma 2x precyzję [1] . Ogólnie rzecz biorąc a ma 15 cyfr dziesiętnych precyzji, a ma 7.float
double
float
Oto jak obliczana jest liczba cyfr:
double
ma 52 bity mantysy + 1 ukryty bit: log (2 53 ) ÷ log (10) = 15,95 cyfr
float
ma 23 bity mantysy + 1 ukryty bit: log (2 24 ) ÷ log (10) = 7,22 cyfry
Ta utrata precyzji może prowadzić do gromadzenia większych błędów skracania, gdy wykonywane są powtarzane obliczenia, np
float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.7g\n", b); // prints 9.000023
podczas
double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.15g\n", b); // prints 8.99999999999996
Ponadto maksymalna wartość liczby zmiennoprzecinkowej wynosi około 3e38
, ale wartość podwójna wynosi około 1.7e308
, więc użycie float
może osiągnąć „nieskończoność” (tj. Specjalną liczbę zmiennoprzecinkową) o wiele łatwiej niż w double
przypadku czegoś prostego, np. Obliczenie silni 60.
Podczas testowania może kilka przypadków testowych zawiera te ogromne liczby, co może spowodować awarię programów, jeśli używasz liczb zmiennoprzecinkowych.
Oczywiście czasami nawet double
nie jest wystarczająco dokładna, dlatego czasami mamy long double
[1] (powyższy przykład podaje 9.000000000000000066 na Macu), ale wszystkie typy zmiennoprzecinkowe cierpią na błędy zaokrąglania , więc jeśli precyzja jest bardzo ważna (np. Pieniądze przetwarzanie) należy użyć int
lub klasy ułamkowej.
Ponadto nie należy używać +=
do sumowania wielu liczb zmiennoprzecinkowych, ponieważ błędy kumulują się szybko. Jeśli używasz Pythona, użyj fsum
. W przeciwnym razie spróbuj zaimplementować algorytm sumowania Kahana .
[1]: C i C ++ normy nie określają reprezentację float
, double
i long double
. Możliwe jest, że wszystkie trzy zostaną zaimplementowane jako podwójna precyzja IEEE. Niemniej jednak dla większości architektur (gcc, MSVC; x86, x64, ARM) float
jest rzeczywiście liczbą zmiennoprzecinkową pojedynczej precyzji IEEE (binary32) i double
jest liczbą zmiennoprzecinkową podwójnej precyzji IEEE (binary64).