Care este diferența între float și double?

Am'am citit despre diferența dintre dublă precizie și singur precizie. Cu toate acestea, în cele mai multe cazuri, "float" și "dublu" par a fi interschimbabile, adică folosind unul sau celălalt nu pare să afecteze rezultatele. Este într-adevăr cazul? Când plutește și duble interschimbabile? Care sunt diferențele dintre ele?

Soluția

Diferență uriașă.

După cum sugerează și numele, o dublu a 2x precizie de float[1]. În general, un "dublu" are 15 cifre zecimale de precizie, în timp ce "float" are 7.

Aici's-numărul de cifre sunt calculate:

"dublu" are 52 de biți mantisa + 1 ascunse pic: log(253)÷log(10) = 15.95 cifre

"float" are 23 de biți mantisa + 1 ascunse pic: log(224)÷log(10) = 7.22 cifre

Această precizie pierderea ar putea duce la o mai mare trunchiere erori fiind acumulate atunci când repetă calculele sunt făcute, de exemplu

float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.7g\n", b); // prints 9.000023

în timp ce

double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.15g\n", b); // prints 8.99999999999996

De asemenea, valoarea maximă a pluti este despre 3e38, dar dublu este de aproximativ 1.7e308, deci, folosind "float" poate a lovit "infinit" (de exemplu, o specială număr în virgulă mobilă) mult mai ușor decât "dublu" pentru ceva simplu, de exemplu, calcul factorial de 60 de ani.

În timpul testării, poate câteva cazuri de testare conține aceste numere imense, care pot cauza programelor dvs. pentru a eșua dacă utilizați plutește.


Desigur, uneori, chiar "dubla" e't suficient de precis, prin urmare, noi, uneori, au long double[1] (exemplul de mai sus oferă 9.000000000000000066 pe Mac), dar toate în virgulă mobilă tipuri suferă de round-off errors, așa că, dacă precizia este foarte important (de exemplu, bani de prelucrare) ar trebui să utilizați int sau o fracțiune de clasă.


În plus, don't folosi += pentru a rezuma o mulțime de numere în virgulă mobilă, ca erori acumula rapid. Daca're folosind Python, folosesc fsum`. În caz contrar, încercați să pună în aplicare Kahan însumare algoritmul.


[1]: C și C++ standarde nu specifica reprezentarea de "float", "dublu" și long double. Este posibil ca toate trei sunt puse în aplicare ca standardul IEEE dublă precizie. Cu toate acestea, pentru cele mai multe arhitecturi (gcc, MSVC; x86, x64, ARM) float este într-adevăr o IEEE single-precizie număr în virgulă mobilă (binary32), și "dublu" e o IEEE dublă precizie în virgulă mobilă număr (binary64).

Comentarii (2)

Aici este ceea ce standardul C99 (ISO-IEC 9899 6.2.5 §10) sau C++2003 (ISO-IEC 14882-2003 3.1.9 §8) standardele spune:

Există trei virgulă mobilă tipuri: "float", "dublu", și long double. Tipul "double" oferă cel puțin la fel de mult precizie ca "float", și tipul long double oferă cel puțin la fel de mult precizie ca "dublu". Setul de valori de tip "float" este un subset al setului de valori de tip "double"; set de valori de tip "dublu" este un subset al setului de valori de tip long double.

C++ standard adaugă:

valoarea reprezentarea în virgulă mobilă tipuri este punerea în aplicare definite.

Le-aș sugera să se uite la excelent Ce Fiecare om de Stiinta de Calculator ar Trebui să Știe Despre virgulă mobilă Aritmetică, care acoperă IEEE virgulă mobilă standard în profunzime. Te'll învăța despre reprezentarea detalii și te'll da seama că nu există un compromis între magnitudine și precizie. Precizie în virgulă mobilă reprezentarea crește ca mărime scade, prin urmare numere în virgulă mobilă între -1 și 1 sunt cei cu cea mai mare precizie.

Comentarii (0)

Având o ecuație de gradul doi: x2 − 4.0000000 x + 3.9999999 = 0 exact rădăcini la 10 cifre semnificative sunt, r1 = 2.000316228 și r2 = 1.999683772.

Folosind "float" și "dublu", putem scrie un program de test:

#include 
#include 

void dbl_solve(double a, double b, double c)
{
    double d = b*b - 4.0*a*c;
    double sd = sqrt(d);
    double r1 = (-b + sd) / (2.0*a);
    double r2 = (-b - sd) / (2.0*a);
    printf("%.5f\t%.5f\n", r1, r2);
}

void flt_solve(float a, float b, float c)
{
    float d = b*b - 4.0f*a*c;
    float sd = sqrtf(d);
    float r1 = (-b + sd) / (2.0f*a);
    float r2 = (-b - sd) / (2.0f*a);
    printf("%.5f\t%.5f\n", r1, r2);
}   

int main(void)
{
    float fa = 1.0f;
    float fb = -4.0000000f;
    float fc = 3.9999999f;
    double da = 1.0;
    double db = -4.0000000;
    double dc = 3.9999999;
    flt_solve(fa, fb, fc);
    dbl_solve(da, db, dc);
    return 0;
}  

Care rulează programul imi da:

2.00000 2.00000
2.00032 1.99968

Rețineți că numerele sunt't de mare, dar încă obține anularea efectelor folosind "float".

(De fapt, mai sus nu este cel mai bun mod de a rezolva ecuații pătratice folosind fie un singur sau dublu-precizie numere în virgulă mobilă, dar răspunsul rămâne neschimbată, chiar dacă se folosește un mai stabil metoda.)

Comentarii (0)
  • O cameră dublă este de 64 și singur precizie (float) este de 32 de biți.
  • Dublu are o mai mare mantisa (întreg biți de număr real).
  • Orice inexactități vor fi mai mici în cea de dublu.
Comentarii (0)

Dimensiunea numerelor implicate în float-punct de calcule nu este cel mai relevant lucru. L's a calcul, care este efectuată de care este relevant.

În esență, dacă're efectuând un calcul, iar rezultatul este un număr irațional sau recurente zecimal, atunci nu va fi erori de rotunjire, atunci când acest număr este strivit în dimensiune finită de date structura te're folosind. Începând cu dublu este de două ori mai mare de a pluti apoi eroarea de rotunjire va fi mult mai mic.

Testele se pot folosi în mod specific numere care ar provoca acest tip de eroare și, prin urmare, testate care te'd folosit tip corespunzătoare în cod.

Comentarii (0)

Tip float, 32 de biți lung, are o precizie de 7 cifre. În timp ce acesta poate stoca valori foarte mari sau foarte mici range (+/- 3.4 10^38 sau 10^-38), are doar 7 cifre semnificative.

Tip dublu, 64 de biti, are o gamă mai mare (*10^+/-308) și precizie de 15 cifre.

Tip long double este nominal de 80 de biți, deși un anumit compilator/OS asocierea poate stoca ca 12-16 bytes pentru alinierea scopuri. Lung dublă are un exponent care doar ridicol de mare și ar trebui să aibă 19 cifre de precizie. Microsoft, în infinita lor înțelepciune, limite de timp dublu la 8 bytes, la fel ca simplu dublu.

În general vorbind, trebuie doar să utilizați de tip double atunci când aveți nevoie de o valoare în virgulă flotantă/variabilă. Literal valori în virgulă mobilă folosite în expresii vor fi tratate ca dublează în mod implicit, și cele mai multe dintre matematica funcții care returnează valori în virgulă mobilă se întoarcă la dublu. Te'll a te salva de multe dureri de cap și typecastings dacă utilizați doar dublu.

Comentarii (1)

Plutește au mai puțină precizie decât dublu. Deși știți deja, citit ceea Ce ar Trebui să Știm Despre virgulă mobilă Aritmetică pentru o mai bună înțelegere.

Comentarii (2)

Am fugit într-o eroare care mi-a luat o veșnicie să-mi dau seama și potențial poate oferi un bun exemplu de precizie float.


#include 
#include 

int main(){
  for(float t=0;t
Comentarii (2)

Atunci când se utilizează numere în virgulă mobilă nu poți avea încredere că dvs. local de teste va fi exact la fel ca testele care se fac pe partea de server. Mediului și compilatorul sunt, probabil, diferite de pe sistemul local și în cazul în care testele finale sunt rulate. Am vazut problema asta de multe ori înainte, în unele TopCoder concursuri mai ales dacă încercați pentru a compara două numere în virgulă mobilă.

Comentarii (0)

Built-in de operații de comparație diferă ca și când ai compara 2 numere cu virgulă mobilă, diferenta de tip de date (de exemplu float sau double) pot duce la rezultate diferite.

Comentarii (0)

Spre deosebire de un int (număr întreg), un "float" au un punct zecimal, și astfel poate un "dublu". Dar diferența între cele două este că un "dublu" este de două ori la fel de detaliat ca un "float", în sensul că acesta poate avea o cantitate dubla de cifre după punctul zecimal.

Comentarii (1)