C ++ Portable Fließkomma Bit Repräsentation?

8

Gibt es eine C ++ - Standardkonforme Methode zum Bestimmen der Struktur von 'float', 'double' und 'long double' zur Kompilierungszeit (oder Laufzeit als Alternative)?

Wenn ich std::numeric_limits< T >::is_iec559 == true und std::numeric_limits< T >::radix == 2 annahm, vermute ich, dass dies durch die folgenden Regeln möglich ist:

  • erste X-Bits sind die Signifikanden.
  • nächste Y-Bits sind der Exponent.
  • letztes 1-Bit ist das Vorzeichen-Bit.

mit den folgenden vagen Formulierungen:

  • size_t num_significand_bits = std::numeric_limits< T >::digits;
  • size_t num_exponent_bits = log2( 2 * std::numeric_limits< T >::max_exponent );
  • size_t num_sign_bits = 1u;

außer ich weiß

  • std::numeric_limits< T >::digits enthält das "Integer-Bit", unabhängig davon, ob das Format es explizit darstellt oder nicht, daher weiß ich nicht, wie ich dies programmatisch erkennen und anpassen kann.
  • Ich denke, std::numeric_limits< T >::max_exponent ist immer 2^(num_exponent_bits)/2 .

Hintergrund : Ich versuche zwei Probleme portabel zu lösen:

  • set / get welche Bits im manificand sind.
  • bestimmen, wo das Ende von 'long double' ist, damit ich nicht die impliziten Padding-Bits lesen kann, die nicht initialisierten Speicher haben.
Charles L Wilcox 08.03.2013, 18:44
quelle

3 Antworten

4

Kurz gesagt, nein. Wenn std::numeric_limits<T>::is_iec559 , dann du kenne das Format von T , mehr oder weniger: du musst noch Bestimmen Sie die Byte-Reihenfolge. Für alles andere sind alle Wetten deaktiviert. (Die anderen Formate, die ich kenne und die noch immer benutzt werden, sind nicht gleich Basis 2: IBM Mainframes verwenden zum Beispiel die Basis 16) "Standard" -Anordnung eines IEC-Gleitkommazeichens hat das Vorzeichen an das höherwertige Bit, dann der Exponent und die Mantisse auf der Bits niedriger Ordnung; wenn Sie es als erfolgreich ansehen können uint64_t , zum Beispiel (via memcpy , reinterpret_cast oder union - 'memcpy funktioniert garantiert, ist aber weniger effizienter als die anderen beiden), dann:

für double :

%Vor%

für 'float:

%Vor%

In Bezug auf long double ist es schlimmer, weil anders Compiler behandeln es anders, sogar auf der gleichen Maschine. Nominell ist es zehn Bytes, aber aus Gründen der Ausrichtung kann es in Tatsache sein 12 oder 16. Oder nur ein Synonym für double . Wenn es ist Mehr als 10 Bytes, denke ich kannst du darauf zählen, dass es gepackt wird in die ersten 10 Bytes, so dass &myLongDouble die Adresse des 10-Byte-Wertes. Aber im Allgemeinen würde ich vermeiden long double .

    
James Kanze 08.03.2013, 19:14
quelle
1

Ich würde sagen, dass der einzige tragbare Weg ist, die Nummer als String zu speichern. Dies beruht nicht auf "Bitmuster interpretieren"

Auch wenn Sie wissen, wie viele Bits etwas ist, bedeutet das nicht, dass es die gleiche Repräsentation hat - der Exponent ist nullbasiert oder voreingenommen. Gibt es eine unsichtbare 1 an der Vorderseite der Mantisse? Das Gleiche gilt für alle anderen Teile der Nummer. Und es wird noch schlimmer für BCD-kodierte oder "hexadezimale" Floats - diese sind in einigen Architekturen verfügbar ...

Wenn Sie sich Sorgen um nicht initialisierte Bits in einer Struktur (Klasse, Array usw.) machen, verwenden Sie memset, um die gesamte Struktur auf Null [oder einen anderen bekannten Wert] zu setzen.

    
Mats Petersson 08.03.2013 18:55
quelle
0

Für die Nachwelt habe ich das getan.

Um meine IEEE-754-Signalisierungs-NaN-Werte zu generieren und zu testen, verwende ich dieses Muster für 'float' und 'double'.

%Vor%

Für 'long double' verwende ich die 'doppelten' Funktionen beim Casting. Insbesondere erzeuge ich den "doppelten" Wert und wandle ihn vor der Rückgabe in "long double" um, und ich teste das "long double", indem ich es "verdopple" und dann diesen Wert teste. Meine Idee ist, dass das "Long Double" -Format variieren kann, wenn man ein "Double" in ein "Long Double" umwandelt, sollte es später konsistent sein (dh keine Information verlieren) / p>     

Charles L Wilcox 11.03.2013 17:35
quelle