531 Stimmen

Was ist der Unterschied zwischen float und double?

Ich habe über den Unterschied zwischen doppelter Präzision und einfacher Präzision gelesen. Allerdings in den meisten Fällen, float y double scheinen austauschbar zu sein, d. h. die Verwendung des einen oder des anderen scheint die Ergebnisse nicht zu beeinflussen. Ist dies wirklich der Fall? Wann sind Floats und Doubles austauschbar? Was sind die Unterschiede zwischen ihnen?

632voto

kennytm Punkte 488916

Ein gewaltiger Unterschied.

Wie der Name schon sagt, ist ein double hat die doppelte Genauigkeit von float [1] . Im Allgemeinen ist eine double hat eine Genauigkeit von 15 Dezimalstellen, während float hat 7.

So wird die Anzahl der Ziffern berechnet:

double hat 52 Mantissenbits + 1 verstecktes Bit: log(2 53 )÷log(10) = 15,95 Ziffern

float hat 23 Mantissenbits + 1 verstecktes Bit: log(2 24 )÷log(10) = 7,22 Stellen

Dieser Präzisionsverlust könnte dazu führen, dass sich bei wiederholten Berechnungen größere Abbruchfehler ansammeln, z. B.

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

während

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

Außerdem liegt der Höchstwert von float bei etwa 3e38 aber das Doppelte ist etwa 1.7e308 also mit float kann "Unendlich" (d. h. eine spezielle Gleitkommazahl) viel leichter erreichen als double für etwas Einfaches, z. B. die Berechnung der Fakultät von 60.

Während des Testens enthalten vielleicht einige Testfälle diese riesigen Zahlen, was dazu führen kann, dass Ihre Programme fehlschlagen, wenn Sie Fließkommazahlen verwenden.


Natürlich, manchmal sogar double ist nicht genau genug, daher müssen wir manchmal long double [1] (das obige Beispiel ergibt 9.000000000000000066 auf Mac), aber alle Gleitkommatypen leiden unter Rundungsfehler Wenn also Präzision sehr wichtig ist (z. B. bei der Geldbearbeitung), sollten Sie int oder eine Fraktionsklasse.


Verwenden Sie außerdem nicht += um viele Fließkommazahlen zu summieren, da sich die Fehler schnell summieren. Wenn Sie Python verwenden, benutzen Sie fsum . Andernfalls sollten Sie versuchen, die Kahan-Summationsalgorithmus .


[1]: Die C- und C++-Standards spezifizieren nicht die Darstellung von float , double y long double . Es ist möglich, dass alle drei als IEEE double-precision implementiert sind. Dennoch gilt für die meisten Architekturen (gcc, MSVC; x86, x64, ARM) float est in der Tat eine IEEE-Gleitkommazahl mit einfacher Genauigkeit (binary32), und double est eine IEEE-Gleitkommazahl mit doppelter Genauigkeit (binary64).

62voto

Gregory Pakosz Punkte 66918

So steht es in den Normen C99 (ISO-IEC 9899 6.2.5 §10) oder C++2003 (ISO-IEC 14882-2003 3.1.9 §8):

Es gibt drei Gleitkommatypen: float , double y long double . Der Typ double bietet mindestens so viel Präzision wie float und der Typ long double bietet mindestens so viel Präzision wie double . Die Menge der Werte des Typs float ist eine Teilmenge der Menge der Werte des Typs double die Menge der Werte des Typs double ist eine Teilmenge der Menge der Werte des Typs long double .

Der C++-Standard fügt hinzu:

Die Wertedarstellung von Gleitkommatypen ist implementierungsabhängig.

Ich würde vorschlagen, einen Blick auf die ausgezeichnete Was jeder Informatiker über Fließkommaarithmetik wissen sollte in dem der IEEE-Gleitkommastandard ausführlich behandelt wird. Sie lernen die Details der Darstellung kennen und werden feststellen, dass es einen Kompromiss zwischen Größe und Genauigkeit gibt. Die Genauigkeit der Fließkommadarstellung nimmt mit abnehmendem Betrag zu, daher sind Fließkommazahlen zwischen -1 und 1 diejenigen mit der höchsten Genauigkeit.

32voto

Alok Singhal Punkte 87419

Gegeben eine quadratische Gleichung: x 2  - 4.0000000  x  + 3,9999999 = 0, die genauen Wurzeln auf 10 signifikante Stellen genau sind, r 1  = 2,000316228 und r 2  = 1.999683772.

Verwendung von float y double können wir ein Testprogramm schreiben:

#include <stdio.h>
#include <math.h>

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;
}  

Wenn ich das Programm ausführe, erhalte ich:

2.00000 2.00000
2.00032 1.99968

Beachten Sie, dass die Zahlen nicht groß sind, aber Sie erhalten dennoch Aufhebungseffekte, wenn Sie float .

(Tatsächlich ist die obige Methode nicht die beste, um quadratische Gleichungen mit einfach- oder doppeltgenauen Gleitkommazahlen zu lösen, aber die Antwort bleibt unverändert, auch wenn man eine stabilere Methode .)

19voto

graham.reeds Punkte 15745
  • Ein Double ist 64 und einfache Genauigkeit (Float) besteht aus 32 Bits.
  • Das Double hat eine größere Mantisse (die ganzzahligen Bits der reellen Zahl).
  • Etwaige Ungenauigkeiten werden im Doppelten kleiner sein.

14voto

Elliscope Fang Punkte 321

Ich bin gerade auf einen Fehler gestoßen, für den ich ewig brauchte, um ihn zu lösen, und der Ihnen möglicherweise ein gutes Beispiel für die Genauigkeit von Schwebekörpern liefert.

#include <iostream>
#include <iomanip>

int main(){
  for(float t=0;t<1;t+=0.01){
     std::cout << std::fixed << std::setprecision(6) << t << std::endl;
  }
}

Die Ausgabe lautet

0.000000
0.010000
0.020000
0.030000
0.040000
0.050000
0.060000
0.070000
0.080000
0.090000
0.100000
0.110000
0.120000
0.130000
0.140000
0.150000
0.160000
0.170000
0.180000
0.190000
0.200000
0.210000
0.220000
0.230000
0.240000
0.250000
0.260000
0.270000
0.280000
0.290000
0.300000
0.310000
0.320000
0.330000
0.340000
0.350000
0.360000
0.370000
0.380000
0.390000
0.400000
0.410000
0.420000
0.430000
0.440000
0.450000
0.460000
0.470000
0.480000
0.490000
0.500000
0.510000
0.520000
0.530000
0.540000
0.550000
0.560000
0.570000
0.580000
0.590000
0.600000
0.610000
0.620000
0.630000
0.640000
0.650000
0.660000
0.670000
0.680000
0.690000
0.700000
0.710000
0.720000
0.730000
0.740000
0.750000
0.760000
0.770000
0.780000
0.790000
0.800000
0.810000
0.820000
0.830000
0.839999
0.849999
0.859999
0.869999
0.879999
0.889999
0.899999
0.909999
0.919999
0.929999
0.939999
0.949999
0.959999
0.969999
0.979999
0.989999
0.999999

Wie Sie sehen können, nimmt die Genauigkeit nach 0,83 deutlich ab.

Wenn ich jedoch die Option t als Doppelgänger, wird ein solches Problem nicht auftreten.

Ich habe fünf Stunden gebraucht, um diesen kleinen Fehler zu erkennen, der mein Programm ruiniert hat.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X