Zum 3DCenter Forum
Inhalt




Das Floating-Point-Format im Detail

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


   Einleitung

Floating-Point-Zahlen gewinnen im Grafik-Bereich immer mehr an Bedeutung, und Begriffe wie "FP24" und "FP32" sind in aller Munde. Was aber heißt "Floating Point" genau? Bei FP24 zum Beispiel ist zwar klar, dass es sich um eine 24-Bit-Zahl im Fließkomma-Format handelt. Was das nun konkret bedeutet, wollen wir in einer dreiteiligen Artikel-Serie untersuchen.

Zunächst werden wir auf die Ganzzahl-Darstellung und auf das Festkomma-Format (englisch: Fix Point) eingehen. Diese "Vorarbeit" ist notwendig, um einen Vergleich mit anderen gebräuchlichen Datentypen möglich zu machen. Danach kommen wir zu den Floating-Point-Zahlen und erklären, wie solche Formate aufgebaut sind. Am Beispiel von FP16 werden die Grundlagen geschaffen, um später interessante Aspekte zu vertiefen und FP24 bis FP80 unter die Lupe zu nehmen. Was wir nur ganz am Rande behandeln, sind Fragen, wie man mit FP-Zahlen rechnet oder mit welchen Schaltungen sich FP-Rechnungen realisieren lassen. Uns geht es um das Grundverständis, nicht um einen Kurs in Schaltungstechnik.

Zumeist werden englischen Begriffe benutzt, vor allem, wenn diese sich eingebürgert haben. Das erschien uns sinnvoller, als krampfhaft Wortschöpfung zu betreiben. Beispielhafte Zahlenwerte mit Nachkomma-Stellen runden wir meist auf drei Stellen, ohne extra zu erwähnen, dass gerundet wurde. Wer möchte, kann selbst mitrechnen, wer nicht, dem reichen auch ungefähre Werte.


   Das Byte - Ein Basis-Format

Die meisten Homecomputer in den 80-er Jahren setzten auf 8-Bit-Technik, während die ersten IBM-PCs immerhin intern schon mit 16 Bit Wortbreite arbeiteten. 16 Bit Wortbreite heißt, dass Daten in Häppchen von jeweils 16 Bit aufgeteilt und verarbeitet werden. Doch aus Kompatibilitätsgründen können - bis heute - auch noch 8-Bit-Register verwendet werden. Acht Bit = ein Byte, das Byte ist die Grundeinheit für Speicherkapazitäts-Angaben. Ein Bit kennt zwei Zustände: 0 oder 1. Mit 8 Bit (= 1 Byte) lassen sich 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 = 2^8 ("2 hoch 8") = 256 Zustände kodieren. Üblicherweise kodiert man die Zustände auf einen Zahlenbereich von 0 bis 255.

Dabei lässt sich die gespeicherte Zahl anhand des Bitmusters direkt ausrechnen. Diese Eigenschaft ist sehr wichtig, da mit dem Zahlenformat ja gerechnet werden soll. Mit einer "direkten" Speicherung kann man relativ einfache Recheneinheiten gestalten, während anders verschlüsselte Darstellungen komplexere Schaltungen erfordern, wie wir gleich noch sehen werden.


Direkte Kodierung einer Zahl

In einem Byte ist jedem der acht Bits eine Wertigkeit zugeordnet. Von rechts nach links sind das die Wertigkeiten 1 - 2 - 4 - 8 - 16 - 32 - 64 - 128. Mit jeder Stelle verdoppelt sich die Wertigkeit (was sich auch als Folge von Zweierpotenzen ausdrücken lässt: 2^0, 2^1, 2^2, usw., bis 2^7.) Addiert man für jedes gesetzte Bit die Stellen-Wertigkeit, steht die Summe für die Zahl, die dieses Bitmuster repräsentiert. Was auf den ersten Blick wie seltsame Rumrechnerei aussehen mag, ist aus Binärsicht die ganz "natürliche" Zahlendarstellung. Kodiert man die Beispielzahl 97 im Dezimalsystem, hat die zweite Stelle von links die Wertigkeit 10. Damit ergibt sich 9*10 + 7*1 = 90 + 7 = 97. Im Computer-Bereich muss man aber binär denken, also die Zwei als Basis nutzen.


   FX8 - Grundlage für Farbinformationen

Auf dem vorzeichenlosen Byte, oder in C-Syntax unsigned char, basiert auch die Kodierungen einer Zahlen-Darstellung, dessen Wertebereich nicht von 0 bis 255, sondern von 0,0 bis 1,0 geht. Eine "direkte" Verschlüsselung ist dann nicht mehr gegeben. Ein Byte, welches "Zweck entfremdet" für die Darstellung von 0 bis 1 genutzt wird, gibt den zweihundertfünfundfünfzigsten Teil einer Zahl an. Dieses Format wollen wir FX8 nennen ("Fixpoint 8 Bit"). Eigentlich ist diese Bezeichnung für ein seltenes anderes 8-Bit-Format vergeben, doch da hier es ohnehin keine offizielle Nomenklatur gibt, wählen wir diesen uns sinnvoll erscheinenden Namen für unsere Zwecke.

Während das Rechenwerk beim Addieren und Subtrahieren von FX8-Werten noch so tun kann, als läge in Wahrheit das Byte-Format vor, muss man beim Multiplizieren aufpassen: 1 * 1 ist ja = 1. "1" wird aber in Byte-Form als "255" kodiert, die Rechnung geht aus Byte-Sicht demzufolge so: "255" * "255" = "255" (und nicht "65025"). Für MUL (Multiplizieren) kann man also nicht mehr auf Integer-Logik zurück greifen, wenn man FX8-Werte verarbeitet.

Wir werden uns übrigens fast nur mit ADD, SUB (Addition und Subtraktion) und MUL beschäftigen. Denn DIV (die Division) wird intern meist mit einer Kombination aus REPR (Kehrwert, Reziproke) und MUL ausgeführt. Statt x / 5 rechnet man x * (1/5). "Echte" DIV-Einheiten wären sehr transistor-aufwändig. Eine Kehrwert-Berechnung braucht man sowieso für einige Zwecke, die wird dann auch gleich fürs DIV genommen.

Kommen wir auf die MUL-Thematik zurück. 1 * 1 muss 1 ergeben, und in FX8 ist die 1,0 so kodiert: 1111'1111 (um das Durchzählen zu erleichtern, gruppieren wir die Bits in 4-er Gruppen, auch Nibbles genannt). Die Rechnung für 1 * 1 in FX8 sieht binär so aus: 1111'1111 * 1111'1111 = 1111'1110'0000'0001. Nimmt man vom Ergebnis einfach die ersten 8 Bits, kommt man auf 1111'1110, was 254 / 255 = 0,996 entspricht. Die Alphablending-Einheiten vom R300 rechnen tatsächlich so, und liefern damit tendenziell zu kleine Ergebnisse. Ein Bit Abweichung ist in der Regel kein Problem, kommt dies aber mehrfach im Pixel vor, erhält man zu dunkle Farben. Um korrekt zu rechnen, muss das Ergebnis mit dem Bit ganz links addiert werden. 1111'1110 + 1 ergibt das richtige Ergebnis von 1111'1111. Wir erwähnen das, um deutlich zu machen, dass ein FX8-Format in der Verwendung weniger trivial ist, als man zunächst denken mag.

Bei FX8 gibt es das Problem, den Wert 0,5 nicht exakt darstellen zu können. "127" entspricht 127/255 = 0,498, und "128" steht für 128/255 = 0,502. Doch weil das Byte für die Hardware sehr "handlich" ist und die Auflösung in 256 Stufen für vieles ausreicht, hat diese Darstellung große Verbreitung gefunden. Dazu zählt zum Beispiel die Speicherung von Farbinformationen im Framebuffer oder in Texturen: Jede Grundfarbe der additiven Lichtmischung, also Rot, Grün und Blau, bekommt je 8 Bit zur Verfügung gestellt. Drei Farbkanäle à 8 Bit = 24 Bit Farbe. Das sind dann 2^24 = 16777216 darstellbare Farben. Scheinbar mehr als genug.

Das menschliche Auge kann zwar nur einige hundert Farben unterscheiden, dafür jedoch Millionen Helligkeitsstufen! Da im 24-Bit-Farbformat jeder Grundfarb-Kanal nur 256 Stufen kennt, gibt es ein Problem: Zwar sind zigtausende Farben darstellbar, aber nur hunderte Helligkeiten. Auf der einen Seite wird feiner abgestuft, als das Auge zu unterscheiden imstande ist, auf der anderen Seite fehlt es an Auflösung. Doch weil sich das 24-Bit-RGB-Format gut rechnen lässt, und die Genauigkeit für das meiste doch noch ausreicht, hat es sich durchgesetzt. Dazu muss auch berücksichtigt werden, über welchen Bereich kritische Helligkeitsverläufe auftreten können: Erst, wenn ein Verlauf von schwarz nach weiß breiter als 256 Pixel ist, kann die eigentlich zu grobe Helligkeits-Abstufung überhaupt wahrgenommen werden. In der Praxis hat man es meistens mit wesentlich kleineren Bereichen zu tun.

Für die Speicherung reicht also ein FX8-Wert pro Grundfarbe in der Regel aus. Wenn mit den Farbwerten gerechnet wird, kommen jedoch mit fast jeder Rechnung neue Rundungsfehler hinzu, und am Ende weicht das Ergebnis vom "wahren" Wert spürbar ab. Doch noch ehe man zusätzliche Genauigkeit braucht, möchte man über einen größeren Bereich rechnen. Zum Beispiel mit negativen Zahlen.






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

Shortcuts
nach oben