Zum 3DCenter Forum
Inhalt




Das Floating-Point-Format im Detail

Teil 2 von 3 / 8. März 2004 / von aths / Seite 8 von 13


   FP24 - Mindest-Voraussetzung für DirectX9

FP24 hat folgenden Aufbau: s16e7. Also ein Vorzeichen-Bit, eine 16-Bit-Mantisse, und einen 7-Bit-Exponenten (mit einem Bias von -63). Der 7-bittige Exponent reserviert wieder zwei Sonderfälle: 0000000 für Null (bzw. Denorms), und 1111111 für Inf und NaN. Der kleinste logische Exponent ist demnach 1 - 63 = -62, der größte logische Exponent ist 126 - 63 = 63. Das ist gegenüber dem, was FP16 bietet (nämlich -14 bis 15) natürlich sehr viel mehr. Konkret heißt das, dass sowohl sehr viel kleinerer als auch sehr viel größere Zahlen dargestellt werden können - in beide Richtung lässt sich das Komma um jeweils bis zu 48 Stellen weiter verschieben, als mit der FP16-Darstellung möglich.

Aber um wieviel genauer ist FP24 nun? Das hängt ja entscheidend von der Mantisse ab. Übrigens ist das der Grund, wieso man beim Aufbau von FP-Formaten erst die Breite der Mantisse nennt, obwohl die Bits der Mantisse bei der internen Speicherung einer FP-Zahl ganz am Ende stehen. Mit eine Mantisse von 16 vs. 10 Bit ist man ja offensichtlich genauer. Um das für uns besser greifbar zu machen, wird die Mantisse oft in signifikante Dezimalstellen umgerechnet. Setzen wir m = Bitstellen der Mantisse, so haben wir:

lg 2^(m+1)

Signifikante Dezimalstellen - das "lg" heißt, Logarithmus zur Basis 10, damit rechnen wir im Zusammenspiel mit 2^ die Variable m+1 (die Anzahl signifikanter binärer Stellen) in die Anzahl dezimaler Stellen um. Die 10-Bit-Mantisse vom FP16-Format entsprechen 11 signifikanten Bits: Das nicht mitgespeicherte "1," trägt ja trotz allem zur Zahl bei. Rechen wir um, ergeben sich 3,3 relevante Dezimalstellen. Das heißt, dass die dritte Dezimalstelle garantiert noch nicht durch einen Rundungsfehler beeinflusst wurde. Die vierte Stelle hingegen ist sehr unsicher. Mit der 16-Bit-Mantisse von FP24 hat man 17 signifikante Binär-, und damit immerhin 5,1 signifikante Dezimalstellen. Gegenüber FP16 ist das ein ziemlicher Fortschritt.

Man mag sich fragen, wieso FP-Zahlen erst Exponent und dann die Mantisse speichern. Das ist kein Zufall: Die gewählte Darstellung ermöglicht, beim Vergleich von zwei Zahlen auf Integer-Logik zurück zu greifen: Da der Exponent den Zahlenwert mehr beeinflusst als die Mantisse, steht dieser weiter vorne und beansprucht damit höherstelligere Bits. Die Vergleichslogik muss dann nur noch den Sonderfall bei NaN berücksichtigen. Gibt es kein NaN, kann man mit ganz normaler Integer-Logik feststellen, welche der beiden Zahlen die größere ist.

Wir vermuten, dass auch GeForceFX-Karten eine Art FP24 kennen. Der Z-Buffer reserviert entweder 16 oder 32 Bit für jedes Pixel. Bei nur 16 Bit kommt es oft zu "Z-Fighting". Das ist ein Artefakt, wenn sich Pixel darum streiten, welcher von ihnen nun sichtbar ist: 16-Bit-Auflösung für Tiefenwerte ist für aufwändigere 3D-Szenen zu wenig. Im 32-Bit-Modus werden aber für jedes Pixel auch 8 Bit Stencil-Buffer zur Verfügung gestellt (unabhängig davon, ob Stencil-Operationen genutzt werden, oder nicht). Bis heute werden Z und Stencil räumlich zusammengefasst gespeichert. Von den 32 Bit für Z/Stencil bleiben 24 für den Z-Wert. Weil FP-Formate für Z-Werte sinnvoller ist als eine Ganzzahl-Darstellung, konvertieren die Karten die als FP32 vorliegenden Z-Werte vielleicht in ein FP24-Format, dessen Aufbau uns allerdings unbekannt ist.

Vielleicht wird auch nur die Mantisse der als FP32 vorliegenden Z-Werte gespeichert. Da dann kein Exponent mitgespeichert wird, muss die Mantisse zuvor auf einen bestimmten Exponenten normalisiert werden. Effektiv enspricht das einer Umrechnung in ein Integer-Format. Dieses ließe sich etwas besser komprimieren, als eine FP24-Darstellung. Es ist anzunehmen, dass die Z-Daten nach der Dekompression aus dem Z-Buffer zur Weiterverarbeitung wieder in ein FP32-Format expandiert werden.

Wir sehen schon, dass die FP24-Genauigkeit nicht für alles ausreicht. Für Farbberechnungen allerdings ist der Einsatz von FP24-Genauigkeit schon fast wie mit Kanonen auf Spatzen zu schießen. Ob ATIs FP24-Hardware Denorms unterstützt, ist uns nicht bekannt. Auch ohne Denorms ist das Format ziemlich brauchbar, weshalb wir meinen, dass ATI getreu der Devise, keinen Transistor zuviel zu verbauen, auf Denorm-Support verzichtet hat. Immerhin verkürzt sich die FP-Logik damit um einige Stages.

Sofern es um Texture Ops geht, ist FP24 aber als grenzwertig zu betrachten. Es lassen sich Überlegungen treffen, wo sich am Ende erweist, dass hochwertige Textur-Filterung bei großen Texturen mit FP24 schwierig wird, sofern man komplexere Verrechnungen für Textur-Koordinaten nutzt. Demirug hat hierzu im 3DCenter-Forum ein Beispiel gepostet.

Wie wir zudem im Artikel ATIs Filtertricks ansprachen, ist FP24 genau auf die Radeon-Hardware abgestimmt. FX16, welches in OpenGL eine gewisse Rolle spielt, ist mit FP24 gut emulierbar: Die 16-Bit-Mantisse wird als Integer- (bzw. Fixpoint)-Zahl interpretiert. Eigentlich hat FP24 ja 17 signifikante Bitstellen, aber das macht ja nichts. Gespeichert werden nur 16 Stellen der Mantisse, darüber ein 16-bittiges Fixpoint-Format zu rechnen, erfordert nicht allzuviel zusätzliche Schaltkreise in den FP-Rechenwerken. Soweit wir wissen, rechnet R200-Hardware (Radeon 8500) mit 14 oder 16 Bit Fixpoint: 1 Bit Vorzeichen, 3 Bit Vorkomma, 10 oder 12 Bit Nachkomma.


   FP32 aka "Single" - Das Standard-Format

"Das" FP-Format ist von der IEEE im Standard 754 genau definiert: Es hat eine Breite von 32 Bit, und setzt sich wie folgt zusammen: s23e8. Gegenüber FP24 gibt es für den Exponenten lediglich ein einziges zusätzliches Bit, dafür ist die Mantisse deutlich länger. Der physische Exponent reicht von 00000000 zu 11111111 (also 0 bis 255.) Bei einem Bias von -127 und den Sonderfällen für Denorms und Inf/NaN bleibt ein "nutzbarer" Exponent von -126 bis 127. Das ist doch deutlich mehr, als FP24 ermöglicht (welches logische Exponenten von -62 bis 63 bietet). Ein einziges zusätzliches Bit im Exponenten macht je mehr aus, je mehr Bits der Exponent bereits hat.

nVidias Implementierung vom FP32-Format unterstützt allerdings keine Denorms. Bei einer denormalisierten FP32-Zahl wird die Mantisse einfach auf 0 gesetzt, das heißt, jeder Denorm wird gleich auf Null gerundet - aus dem "gradual underflow" wird sofort ein "underflow". Trotzdem ist das noch genauer als FP24 mit Denorms - und dies, obwohl FP32 gegenüber FP24 gerademal ein einziges zusätzliches Bit für den Exponenten vorsieht! Man muss sich dafür vor Augen halten, was die Essenz vom Floating-Point-Format ist: Je kleiner die Zahlen, desto feiner die Abstände zwischen den tatsächlich darstellbaren Werten. Mit einem Exponenten von 7 Bit sind Komma-Verschiebungen über einen Bereich von 126 Stellen möglich (2^7 = 128, abzüglich zwei reservierter Exponenten für Null/Denorm und Inf/NaN).

Mit 8 Bit hat man 254 Möglichkeiten, das Komma zu positionieren. Würde mit gleicher Mantissen-Länge gearbeitet, gewönne man zwar keine relative Genauigkeit - aber einen größeren Bereich für große Zahlen. Und man könnte die unveränderte relative Genauigkeit auch bei sehr kleinen Zahlen ausnutzen, bevor es zum Underflow kommt. Deshalb braucht FP32 auf Nvidia-Karten keinen Denorm-Support, um FP24 in jeder Hinsicht den Schatten zu stellen. Der größte Vorteil liegt aber in der längeren Mantisse, die bei FP32 immerhin 23 Bit breit ist (gegenüber 16 Bit Mantisse bei FP24). Das heißt, in jedem Bereich kann 128 mal feiner abgestuft werden.

Das vom IEEE standardisierte FP32-Format sieht natürlich Denorms vor. FP32-Rechenwerke in der CPU sind deutlich aufwändiger als die vereinfachten Versionen in heutigen GPUs. Dafür enthalten CPUs auch nur wenige FP-Units, im Gegensatz zu einer GPU, die ziemlich viele davon auf dem Chip braucht.

Die IEEE schreibt noch weitere Features vor. So gibt es nicht einfach nur "NaN", sondern SNaN und QNaN, was Signaling NaN bzw. Quite NaN heißt. Bekanntlich steht "NaN" für Werte, die sich nicht als Zahl darstellen lassen bzw. für Variablen, denen noch kein Wert zugewiesen wurde. Jede Operation, wo mindestens ein Input NaN ist, hat immer NaN als Ergebnis. Eine CPU wirft außerdem eine Exception aus, damit gegebenfalls eine Ausnahme-Behandlung in Aktion treten kann. Grafikchips halten natürlich nicht an, sondern setzen am Ende der Berechnungen NaN einfach zu Null. Abfangen lässt sich NaN auf GPUs derzeit nicht.

Es kann sein, dass dies auch bei einer CPU unerwünscht ist. Dann bietet es sich an, mit Quiet NaNs arbeiten. Diese NaNs sind "still", und führen nicht zu einer Exception. Mit QNaNs kann der Programmierer mögliche fehlerhafte Ergebnisse selbst abfangen. Im Kontrast zu Nan steht Inf nicht zwangsläufig für das Ergebnis einer illegalen Operation (z. B. ist 0 / 0 illegal, und führt zu NaN), sondern zeigt auch einen Overflow an. Inf kann bei 1 / 0 auftreten, was eine illegale Operation ist, oder beim Addieren zweier so großer Zahlen, dass die Summe den Wertebereich der FP-Zahl übersteigt. Eine Addition von zwei Zahlen ist aber mathematisch gesehen keine eine illegale Operation, 1 / 0 hingegen schon. CPUs kennen also mehrere Exceptions, die ein Inf anzeigen, da Inf unterschiedliche Ursachen haben kann. Einige Programmiersprachen unterstützen übrigens die Möglichkeit, dass NaN und Inf auch als Zeichenkette "NaN" bzw. "Inf" ausgegeben werden.






Kommentare, Meinungen, Kritiken können ins Forum geschrieben werden - Registrierung ist nicht notwendig Zurück / Back Weiter / Next

Shortcuts
nach oben