'float' vs. 'doppelte' Präzision

155

Der Code

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

gibt Ihnen die Ausgabe

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

Dabei steht in der dritten Ausgabezeile 741012573242Müll und in der vierten Zeile 116Müll. Haben Doppel immer 16 signifikante Zahlen, während Floats immer 7 signifikante Zahlen haben? Warum haben Doppel nicht 14 signifikante Zahlen?

foo
quelle

Antworten:

146

Gleitkommazahlen in C verwenden die IEEE 754- Codierung.

Diese Art der Codierung verwendet ein Vorzeichen, einen Signifikanten und einen Exponenten.

Aufgrund dieser Codierung haben viele Zahlen kleine Änderungen, damit sie gespeichert werden können.

Außerdem kann sich die Anzahl der signifikanten Stellen geringfügig ändern, da es sich um eine binäre Darstellung handelt, nicht um eine dezimale.

Mit einfacher Genauigkeit (float) erhalten Sie 23 Bit Signifikand, 8 Bit Exponent und 1 Vorzeichenbit.

Doppelte Genauigkeit (doppelt) ergibt 52 Bit Signifikand, 11 Bit Exponent und 1 Vorzeichenbit.

Alan Geleynse
quelle
4
C99 tut es, vorher war es Sache des Compilers.
Alan Geleynse
21
-1 Diese Aussage ist offensichtlich falsch: "Aufgrund dieser Codierung können Sie niemals garantieren, dass sich Ihr Wert nicht ändert."
R .. GitHub STOP HELPING ICE
16
@Alan: Für C99 ist kein IEEE-Gleitkomma erforderlich. es empfiehlt es nur.
R .. GitHub STOP HELPING ICE
4
@ Alan: R .. ist richtig; Anhang F (in dem IEEE-754-Bindungen angegeben sind) ist normativ, gilt jedoch nur, wenn eine Implementierung dies definiert __STDC_IEC_559__. Eine Implementierung, die dieses Makro nicht definiert, kann nicht IEEE-754 entsprechen.
Stephen Canon
12
@Alan: Unter IEEE 754, ist es leicht garantiert , dass es in den Werten keine Veränderung ist 0.5, 0.046875oder 0.376739501953125gegen ihre Dezimaldarstellungen. (Dies sind alles diadische Gründe mit Zähleranpassung in der Mantisse und Basis-2-Logarithmus der
Nenneranpassung
42

Haben Doppel immer 16 signifikante Zahlen, während Floats immer 7 signifikante Zahlen haben?

Nein. Doubles haben immer 53 signifikante Bits und Floats haben immer 24 signifikante Bits (mit Ausnahme von Denormals, Infinities und NaN-Werten, aber diese sind Gegenstand einer anderen Frage). Dies sind Binärformate, und Sie können nur klar über die Genauigkeit ihrer Darstellungen in Form von Binärziffern (Bits) sprechen.

Dies ist analog zu der Frage, wie viele Ziffern in einer binären Ganzzahl gespeichert werden können: Eine vorzeichenlose 32-Bit-Ganzzahl kann Ganzzahlen mit bis zu 32 Bit speichern, die keiner Anzahl von Dezimalstellen genau zugeordnet werden können: alle Ganzzahlen von bis zu Es können 9 Dezimalstellen gespeichert werden, aber es können auch viele 10-stellige Zahlen gespeichert werden.

Warum haben Doppel nicht 14 signifikante Zahlen?

Die Codierung eines Doppels verwendet 64 Bit (1 Bit für das Vorzeichen, 11 Bit für den Exponenten, 52 explizit signifikante Bits und ein implizites Bit), was der doppelten Anzahl von Bits entspricht, die zur Darstellung eines Gleitkommas verwendet werden (32 Bit).

Stephen Canon
quelle
15

float: 23 Bit Signifikand, 8 Bit Exponent und 1 Vorzeichenbit.

double: 52 Bit Signifikand, 11 Bit Exponent und 1 Vorzeichenbit.

abe312
quelle
11

Es basiert normalerweise auf signifikanten Zahlen sowohl des Exponenten als auch des Signifikanten in Basis 2, nicht auf Basis 10. Nach dem, was ich im C99-Standard sagen kann, gibt es jedoch keine spezifizierte Genauigkeit für Floats und Doubles (außer der Tatsache, dass 1 und 1 + 1E-5/ 1 + 1E-7sind unterscheidbar [ floatund doublejeweils]). Die Anzahl der signifikanten Zahlen bleibt jedoch dem Implementierer überlassen (sowie die Basis, die er intern verwendet. Mit anderen Worten, eine Implementierung könnte entscheiden, sie auf der Grundlage von 18 Stellen Genauigkeit in Basis 3 zu erstellen). [1]

Wenn Sie diese Werte kennen müssen, werden die Konstanten FLT_RADIXund FLT_MANT_DIG(und DBL_MANT_DIG/ LDBL_MANT_DIG) in float.h definiert.

Der Grund, warum es als a bezeichnet wird, doubleist, dass die Anzahl der zum Speichern verwendeten Bytes doppelt so hoch ist wie die Anzahl eines Floats (dies schließt jedoch sowohl den Exponenten als auch den Signifikanten ein). Der IEEE 754-Standard (von den meisten Compilern verwendet ) weist dem Signifikanten relativ mehr Bits zu als dem Exponenten (23 bis 9 für floatgegenüber 52 bis 12 für double), weshalb die Genauigkeit mehr als verdoppelt wird.

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

user470379
quelle
Tippfehler? C89 erfordert ein Epsilon von höchstens 1E-9für double, nicht 1E-7.
Rufflewind
10

Ein Float hat eine Genauigkeit von 23 Bit und ein Double eine Genauigkeit von 52.

Chris Nash
quelle
Detail: binary64 hat eine 53-Bit-Signifikanz (52 explizit gespeichert) binary32 hat 24 Bit (23 explizit gespeichert).
chux
4

Es ist nicht gerade doppelte Genauigkeit, weil IEEE 754 funktioniert und weil Binärdateien nicht wirklich gut in Dezimalzahlen übersetzt werden können. Schauen Sie sich bei Interesse den Standard an.

user541686
quelle
4

float steht für Gleitkommazahl. In C wird der Gleitkomma-Datentyp in den Fällen verwendet, in denen die Genauigkeit der Gesamtzahl der Ziffern 7 beträgt. Zum Beispiel: - die Dezimalzahl. 12.3546987 kann nicht in float gespeichert werden, da es insgesamt 9 Ziffern hat. Die Ausgabe wird als 12.354699 angezeigt, dh die ersten 7 Ziffern werden wie in der Eingabe eingegeben angezeigt und die 8. Ziffer wird abgerundet. Der float-Typ kann Werte darstellen im Bereich von ungefähr 1,5 x 10 ^ (- 45) bis 3,4 x 10 ^ (38). In Bezug auf die Speicherzuweisung ist float ein 32-Bit-Gleitkomma-Datentyp mit einfacher Genauigkeit.

Im Gegensatz zu float hat double eine Genauigkeit von 15 bis 16 Stellen. Der Bereich von double liegt zwischen 5,0 × 10 ^ (- 345) und 1,7 × 10 ^ (308). In Bezug auf die Bytezuordnung ist double ein 64-Bit-Gleitkommadaten Art.

Das Problem tritt bei seiner Verwendung auf. Float oder Double wirkt sich nicht auf printf aus, aber im Falle von scanf ist der entsprechende Datentyp abhängig von der Gesamtzahl zu verwenden. von Ziffern in schwebender Nr. das ist von der Eingabe zu lesen.

Daher wird Double für eine höhere Genauigkeit der Daten gegenüber Float bevorzugt.

Hoffe das hilft.

Vineeth Krishna K.
quelle