Was ist der Unterschied zwischen Float und Double?

420

Ich habe über den Unterschied zwischen doppelter und einfacher Genauigkeit gelesen. In den meisten Fällen scheint die Verwendung des einen oder anderen die Ergebnisse jedoch nicht zu beeinflussen floatund doublescheint austauschbar zu sein. Ist das wirklich der Fall? Wann sind Schwimmer und Doppel austauschbar? Was sind die Unterschiede zwischen ihnen?

VaioIsBorn
quelle

Antworten:

521

Großer Unterschied.

Wie der Name schon sagt, doublehat a die doppelte Genauigkeit von [1] . Im Allgemeinen hat a eine Genauigkeit von 15 Dezimalstellen, während a 7 hat.floatdoublefloat

So wird die Anzahl der Ziffern berechnet:

doublehat 52 Mantissenbits + 1 verstecktes Bit: log (2 53 ) ÷ log (10) = 15,95 Stellen

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

Dieser Präzisionsverlust könnte dazu führen, dass sich größere Wiederholungsfehler ansammeln, wenn wiederholte Berechnungen durchgeführt werden, z

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

Auch der Maximalwert von float ist ungefähr 3e38, aber double ist ungefähr 1.7e308, so dass die Verwendung von float"unendlich" (dh eine spezielle Gleitkommazahl) viel einfacher getroffen werden kann als doublefür etwas Einfaches, z. B. die Berechnung der Fakultät von 60.

Während des Testens enthalten möglicherweise einige Testfälle diese großen Zahlen, die dazu führen können, dass Ihre Programme fehlschlagen, wenn Sie Floats verwenden.


Natürlich ist manchmal sogar doublenicht genau genug, daher haben wir manchmal long double[1] (das obige Beispiel gibt 9.00000000000000000066 auf dem Mac an), aber alle Gleitkommatypen leiden unter Rundungsfehlern , wenn also Präzision sehr wichtig ist (z. B. Geld) Verarbeitung) sollten Sie intoder eine Bruchklasse verwenden.


Verwenden Sie außerdem nicht +=viele Gleitkommazahlen, da sich die Fehler schnell ansammeln. Wenn Sie Python verwenden, verwenden Sie fsum. Versuchen Sie andernfalls, den Kahan-Summationsalgorithmus zu implementieren .


[1]: Die C- und C ++ Standards spezifizieren nicht die Darstellung float, doubleund long double. Es ist möglich, dass alle drei als IEEE-Doppelgenauigkeit implementiert sind. Für die meisten Architekturen (gcc, MSVC; x86, x64, ARM) float handelt es sich jedoch tatsächlich um eine IEEE-Gleitkommazahl mit einfacher Genauigkeit (binary32) und double um eine IEEE-Gleitkommazahl mit doppelter Genauigkeit (binary64).

kennytm
quelle
9
Der übliche Rat für die Summierung besteht darin, Ihre Gleitkommazahlen vor der Summierung nach der Größe (kleinste zuerst) zu sortieren.
R .. GitHub STOP HELPING ICE
Beachten Sie, dass C / C ++ Float und Double fast immer IEEE Single- bzw. Double-Genauigkeit sind. C / C ++ Long Double ist je nach CPU, Compiler und Betriebssystem weitaus variabler. Manchmal ist es dasselbe wie doppelt, manchmal ist es ein systemspezifisches erweitertes Format, manchmal ist es IEEE Quad-Genauigkeit.
Plugwash
@ R..GitHubSTOPHELPINGICE: warum? Könntest du erklären?
InQusitive
@InQusitive: Betrachten Sie zum Beispiel ein Array, das aus dem Wert 2 ^ 24 gefolgt von 2 ^ 24 Wiederholungen des Werts 1 besteht. Das Summieren in der Reihenfolge ergibt 2 ^ 24. Das Umkehren ergibt 2 ^ 25. Natürlich können Sie Beispiele anführen (z. B. 2 ^ 25 Wiederholungen von 1), bei denen jede Reihenfolge mit einem einzelnen Akkumulator katastrophal falsch ist, aber die kleinste Größe zuerst die beste unter diesen ist. Um es besser zu machen, braucht man eine Art Baum.
R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
56

In den Normen C99 (ISO-IEC 9899 6.2.5 §10) oder C ++ 2003 (ISO-IEC 14882-2003 3.1.9 §8) heißt es:

Es gibt drei Gleitkommatypen: float, double, und long double. Der Typ doublebietet mindestens so viel Präzision wie floatund der Typ long doublebietet mindestens so viel Präzision wie double. Die Wertemenge des Typs floatist eine Teilmenge der Wertemenge des Typs double. Die Menge der Werte des Typs doubleist eine Teilmenge der Menge der Werte des Typs long double.

Der C ++ - Standard fügt hinzu:

Die Wertdarstellung von Gleitkommatypen ist implementierungsdefiniert.

Ich würde vorschlagen, einen Blick auf das ausgezeichnete zu werfen, was jeder Informatiker über Gleitkomma-Arithmetik wissen sollte , das den IEEE-Gleitkomma-Standard ausführlich behandelt. Sie lernen die Details der Darstellung kennen und stellen fest, dass es einen Kompromiss zwischen Größe und Präzision gibt. Die Genauigkeit der Gleitkommadarstellung nimmt mit abnehmender Größe zu, daher sind Gleitkommazahlen zwischen -1 und 1 diejenigen mit der höchsten Genauigkeit.

Gregory Pakosz
quelle
27

Bei einer quadratischen Gleichung: x 2  - 4.0000000  x  + 3.9999999 = 0 sind die genauen Wurzeln zu 10 signifikanten Stellen r 1  = 2.000316228 und r 2  = 1.999683772.

Mit floatund doublekö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;
}  

Das Ausführen des Programms gibt mir:

2.00000 2.00000
2.00032 1.99968

Beachten Sie, dass die Zahlen nicht groß sind, Sie jedoch dennoch Stornierungseffekte verwenden float.

(Tatsächlich ist das Obige nicht der beste Weg, um quadratische Gleichungen mit Gleitkommazahlen mit einfacher oder doppelter Genauigkeit zu lösen, aber die Antwort bleibt unverändert, selbst wenn man eine stabilere Methode verwendet .)

Alok Singhal
quelle
19
  • Ein Double ist 64 und eine Single Precision (Float) ist 32 Bit.
  • Das Doppel hat eine größere Mantisse (die ganzzahligen Bits der reellen Zahl).
  • Ungenauigkeiten sind doppelt so groß.
graham.reeds
quelle
12

Die Größe der Zahlen, die an den Gleitkommaberechnungen beteiligt sind, ist nicht die relevanteste Sache. Es ist die Berechnung, die durchgeführt wird, die relevant ist.

Wenn Sie eine Berechnung durchführen und das Ergebnis eine irrationale Zahl oder eine wiederkehrende Dezimalzahl ist, treten im Wesentlichen Rundungsfehler auf, wenn diese Zahl in die von Ihnen verwendete Datenstruktur endlicher Größe gequetscht wird. Da double doppelt so groß ist wie float, ist der Rundungsfehler viel kleiner.

Bei den Tests werden möglicherweise speziell Zahlen verwendet, die diese Art von Fehler verursachen würden. Daher wurde getestet, ob Sie den entsprechenden Typ in Ihrem Code verwendet haben.

Dolbz
quelle
9

Der 32-Bit-Typ float hat eine Genauigkeit von 7 Stellen. Während es Werte mit sehr großem oder sehr kleinem Bereich (+/- 3,4 * 10 ^ 38 oder * 10 ^ -38) speichern kann, hat es nur 7 signifikante Stellen.

Typ double, 64 Bit lang, hat einen größeren Bereich (* 10 ^ + / - 308) und eine Genauigkeit von 15 Stellen.

Der Typ long double ist nominell 80 Bit, obwohl eine bestimmte Compiler / OS-Paarung ihn zu Ausrichtungszwecken als 12-16 Byte speichern kann. Das lange Doppel hat einen Exponenten, der einfach lächerlich groß ist und eine Genauigkeit von 19 Stellen haben sollte. Microsoft begrenzt in ihrer unendlichen Weisheit das lange Double auf 8 Bytes, genau wie das einfache Double.

Verwenden Sie im Allgemeinen nur den Typ double, wenn Sie einen Gleitkommawert / eine Gleitkommavariable benötigen. In Ausdrücken verwendete wörtliche Gleitkommawerte werden standardmäßig als Doppelwerte behandelt, und die meisten mathematischen Funktionen, die Gleitkommawerte zurückgeben, geben Doppelwerte zurück. Sie sparen sich viele Kopfschmerzen und Typografien, wenn Sie nur double verwenden.

Zain Ali
quelle
Tatsächlich liegt es für Float zwischen 7 und 8, um genau zu sein 7,225 .
Peter Mortensen
9

Ich bin gerade auf einen Fehler gestoßen, der mich ewig gekostet hat, um herauszufinden, und der Ihnen möglicherweise ein gutes Beispiel für die Float-Präzision geben kann.

#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 ist

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 nach 0,83 sehen können, nimmt die Genauigkeit erheblich ab.

Wenn ich mich jedoch tals Double einrichte , tritt ein solches Problem nicht auf.

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

Elliscope Fang
quelle
4
Nur um sicher zu gehen: Die Lösung Ihres Problems sollte darin bestehen, vorzugsweise ein int zu verwenden. Wenn Sie 100 Mal iterieren möchten, sollten Sie mit einem int zählen, anstatt ein double zu verwenden
BlueTrin
8
Die Verwendung doubleist hier keine gute Lösung. Sie verwenden, um intzu zählen und eine interne Multiplikation durchzuführen, um Ihren Gleitkommawert zu erhalten.
Richard
3

Wenn Sie Gleitkommazahlen verwenden, können Sie nicht darauf vertrauen, dass Ihre lokalen Tests genau den Tests entsprechen, die auf der Serverseite durchgeführt werden. Die Umgebung und der Compiler unterscheiden sich wahrscheinlich auf Ihrem lokalen System und dort, wo die endgültigen Tests ausgeführt werden. Ich habe dieses Problem schon oft in einigen TopCoder-Wettbewerben gesehen, insbesondere wenn Sie versuchen, zwei Gleitkommazahlen zu vergleichen.

Tuomas Pelkonen
quelle
3

Die integrierten Vergleichsoperationen unterscheiden sich wie beim Vergleichen von 2 Zahlen mit Gleitkommazahlen. Der Unterschied im Datentyp (dh Float oder Double) kann zu unterschiedlichen Ergebnissen führen.

Johnathan Lau
quelle
1

Wenn man mit eingebetteter Verarbeitung arbeitet, wird die zugrunde liegende Hardware (z. B. FPGA oder ein bestimmtes Prozessor- / Mikrocontroller-Modell) möglicherweise optimal in Hardware implementiert, während double Softwareroutinen verwendet. Wenn also die Genauigkeit eines Floats ausreicht, um die Anforderungen zu erfüllen, wird das Programm mit float einige Male schneller ausgeführt als mit double. Achten Sie, wie in anderen Antworten angegeben, auf Akkumulationsfehler.

Lissandro
quelle
-1

Im Gegensatz zu einer int(ganzen Zahl) hat a floateinen Dezimalpunkt, und a auch double. Der Unterschied zwischen den beiden besteht jedoch darin, dass a doubledoppelt so detailliert ist wie a float, was bedeutet, dass es nach dem Dezimalpunkt doppelt so viele Zahlen haben kann.

Nykal
quelle
4
Das heißt das überhaupt nicht. Es bedeutet tatsächlich doppelt so viele ganzzahlige Dezimalstellen und ist mehr als doppelt so hoch . Die Beziehung zwischen gebrochenen Ziffern und Genauigkeit ist nicht linear: Sie hängt vom Wert ab: z. B. 0,5 ist genau, 0,3333333333333333333333 jedoch nicht.
Marquis von Lorne