Long Double (GCC-spezifisch) und __float128

Ich bin auf der Suche nach detaillierten Informationen über long double und __float128 im GCC/x86 (mehr aus Neugier als wegen eines aktuellen Problems).

Paar Leute werden wahrscheinlich jemals brauchen werden, diese (ich habe gerade zum ersten mal wirklich benötigt eine double), aber ich denke, es ist immer noch interessant (und interessant) zu wissen, was Sie in der toolbox und dem, was es ist.

In diesem Licht, bitte entschuldigen Sie meine etwas offene Fragen:

  1. Könnte mir jemand erklären, die Umsetzung, Begründung und geplante Verwendung von diesen Arten, auch im Vergleich miteinander? Zum Beispiel, werden Sie "Verlegenheit Implementierungen", denn der standard ermöglicht es, den Typ, und jemand könnte sich beschweren, wenn Sie gerade erst die gleiche Präzision wie double, oder Sie sind gedacht als erste-Klasse-Typen?
  2. Alternativ, hat jemand eine gute, brauchbare web-Verweis zu teilen? Eine Google-Suche auf "long double" site:gcc.gnu.org/onlinedocs mir nicht viel, dass ist wirklich nützlich.
  3. Unter der Annahme, dass das gemeinsame mantra "wenn Sie glauben, dass Sie brauchen Doppel -, werden Sie wahrscheinlich nicht verstehen, floating point" gilt nicht, d.h. Sie wirklich brauchen mehr Präzision als nur float, und man ist nicht egal, ob 8 oder 16 bytes des Speichers sind verbrannt... ist es vernünftig zu erwarten, dass man genauso gut springen zu long double oder __float128 statt double ohne eine signifikante Auswirkung auf die Leistung?
  4. Die "extended-precision" - Funktion von Intel-CPUs seit jeher Quelle der bösen überraschungen, wenn die Werte verschoben wurden zwischen Speicher und Register. Wenn tatsächlich 96 bits gespeichert werden, die long double geben sollte, beseitigen Sie dieses Problem. Auf der anderen Seite verstehe ich, dass long double Typ ist gegenseitig mit -mfpmath=sse werden, da es keine solche Sache als "extended precision" in der SSE. __float128, auf der anderen Seite, sollten die arbeiten nur einwandfrei mit SSE Mathe (obwohl in der Abwesenheit von quad Präzisions-Anweisungen, die sicherlich nicht auf eine 1:1 Anleitung base). Gehe ich Recht in der diese Annahmen?

(3. und 4. kann man wohl herausgefunden, mit der Arbeit, die aufgewendet profiling-und Abbau, aber vielleicht hat jemand anderes den gleichen Gedanken hatte vorher schon gemacht hat, die Arbeit.)

Hintergrund (das ist die TL;DR-Teil):
Ursprünglich habe ich stolperte über long double da ich auf der Suche bis DBL_MAX im <float.h>, und incidentially LDBL_MAX ist auf der nächsten Zeile. "Oh, schau, GCC hat tatsächlich 128 bit verdoppelt, nicht, dass ich Sie brauche, aber... cool" war auch mein Erster Gedanke. Überraschung, überraschung: sizeof(long double) gibt 12... warte, meinst du 16?

C und C++ standards, die wenig überraschend nicht geben eine sehr konkrete definition von Art. C99 (6.2.5 10) sagt, dass die zahlen von double sind eine Teilmenge der long double in der Erwägung, dass C++03-Staaten (3.9.1 8), die long double hat mindestens ebenso viel Präzision wie double (das ist das gleiche, nur anders formuliert). Grundsätzlich werden die standards verlassen alles, um die Umsetzung in der gleichen Weise wie mit long, int, und short.

Wikipedia sagt, dass GCC verwendet "80-bit-extended-precision auf x86-Prozessoren unabhängig von der physischen Speicherung verwendet".

Die GCC-Dokumentation angegeben, sind alle auf der gleichen Seite, dass die Größe des Typs ist 96 bits, da der i386-ABI, aber nicht mehr als 80 bit Genauigkeit werden aktiviert, wenn eine beliebige option (huh? was?), auch Pentium und neuere Prozessoren wollen Sie ausgerichtet, wie 128-bit-zahlen. Dies ist die Standardeinstellung unter 64 bit und kann manuell aktiviert werden unter 32 bits, was 32 bits von null Polsterung.

Zeit, um einen test:

#include <stdio.h>
#include <cfloat>

int main()
{
#ifdef  USE_FLOAT128
    typedef __float128  long_double_t;
#else
    typedef long double long_double_t;
#endif

long_double_t ld;

int* i = (int*) &ld;
i[0] = i[1] = i[2] = i[3] = 0xdeadbeef;

for(ld = 0.0000000000000001; ld < LDBL_MAX; ld *= 1.0000001)
    printf("%08x-%08x-%08x-%08x\r", i[0], i[1], i[2], i[3]);

return 0;
}

Den Ausgang, wenn mit long double, sieht etwas aus wie diese, mit markierten Ziffern konstant, und alle anderen, schließlich ändern sich die zahlen immer größer werden:

5636666b-c03ef3e0-00223fd8-deadbeef
                  ^^       ^^^^^^^^

Dies deutet darauf hin, dass es nicht eine 80 bit Zahl. Ein 80-bit-Zahl hat 18 hex-Ziffern. Ich sehe, 22 hex-Ziffern ändern, die sieht viel eher wie ein 96-bit-Zahl (24 hex Ziffern). Es ist auch nicht eine 128 bit-Zahl, da 0xdeadbeef nicht berührt wird, die im Einklang mit sizeof Rückkehr 12.

Die Ausgabe für __int128 wie es aussieht ist wirklich nur ein 128-bit-Zahl. Alle bits schließlich umdrehen.

Kompilieren mit -m128bit-long-double hat nicht ausrichten long double zu 128 bit mit einer 32-bit-null Polsterung, wie dies durch die Dokumentation. Es nicht __int128 entweder, aber in der Tat scheint das ausrichten von 128 bits, padding mit dem Wert 0x7ffdd000(?!).

Weiter LDBL_MAX, scheint zu funktionieren, wie +inf für beide long double und __float128. Addieren oder subtrahieren einer Zahl wie 1.0E100 oder 1.0E2000 an/aus LDBL_MAX Ergebnisse in die gleiche bit-Muster.
Bis jetzt war es meine überzeugung, dass die foo_MAX Konstanten wurden für die größte Darstellbare Zahl ist, die nicht +inf (anscheinend ist das nicht der Fall?). Ich bin mir auch nicht ganz sicher, wie ein 80-bit-Zahl kann sich in der Praxis handeln, als +inf für einen 128 bit Wert... vielleicht bin ich einfach zu müde am Ende des Tages, und etwas falsch gemacht haben.

Kommentar zu dem Problem
Die 80-bit-double speichern kann uint64_t. Es hat 64 bits der Mantisse (Nein optional/implizite führende bit), 15 bit exponent und ein Vorzeichenbit. en.wikipedia.org/wiki/... Kommentarautor: Aki Suihkonen
Anstelle der addition oder Subtraktion von LDBL_MAX, haben Sie versucht, geteilt durch zwei? Kommentarautor: Ben Voigt

InformationsquelleAutor der Frage Damon | 2012-11-22

Schreibe einen Kommentar