Gleitkommazahl
In der Informatik ist die Gleitkommaarithmetik (FP) eine Arithmetik, die eine formelhafte Darstellung von reellen Zahlen als Näherung verwendet, um einen Kompromiss zwischen Bereich und Genauigkeit zu unterstützen. Aus diesem Grund wird die Fließkommaberechnung häufig in Systemen mit sehr kleinen und sehr großen reellen Zahlen verwendet, die schnelle Verarbeitungszeiten erfordern. Im Allgemeinen wird eine Gleitkommazahl näherungsweise mit einer festen Anzahl signifikanter Ziffern (dem Signifikanten) dargestellt und mit einem Exponenten in einer festen Basis skaliert; die Basis für die Skalierung ist normalerweise zwei, zehn oder sechzehn. Eine Zahl, die exakt dargestellt werden kann, hat die folgende Form
Der Begriff Fließkomma bezieht sich auf die Tatsache, dass der Radixpunkt (Dezimalpunkt oder, in Computern üblicher, Binärpunkt) einer Zahl "fließend" sein kann, d. h. er kann an einer beliebigen Stelle im Verhältnis zu den signifikanten Ziffern der Zahl platziert werden. Diese Position wird durch den Exponenten angegeben, so dass die Fließkommadarstellung als eine Form der wissenschaftlichen Notation angesehen werden kann. ⓘ
Ein Fließkommasystem kann dazu verwendet werden, mit einer festen Anzahl von Ziffern Zahlen verschiedener Größenordnungen darzustellen: z. B. kann der Abstand zwischen Galaxien oder der Durchmesser eines Atomkerns mit derselben Längeneinheit ausgedrückt werden. Dieser dynamische Bereich hat zur Folge, dass die darstellbaren Zahlen nicht gleichmäßig verteilt sind; die Differenz zwischen zwei aufeinanderfolgenden darstellbaren Zahlen variiert mit der gewählten Skala. ⓘ
Im Laufe der Jahre wurde in Computern eine Vielzahl von Gleitkommadarstellungen verwendet. Im Jahr 1985 wurde der IEEE 754 Standard for Floating-Point Arithmetic eingeführt, und seit den 1990er Jahren sind die vom IEEE definierten Darstellungen die am häufigsten verwendeten. ⓘ
Die Geschwindigkeit von Gleitkommaoperationen, die üblicherweise in FLOPS gemessen wird, ist ein wichtiges Merkmal eines Computersystems, insbesondere für Anwendungen, die intensive mathematische Berechnungen beinhalten. ⓘ
Eine Fließkommaeinheit (FPU, umgangssprachlich: mathematischer Koprozessor) ist ein Teil eines Computersystems, der speziell für die Durchführung von Operationen mit Fließkommazahlen ausgelegt ist. ⓘ
Die Menge der Gleitkommazahlen ist eine Teilmenge der rationalen Zahlen. Zusammen mit den auf ihnen definierten Operationen (Gleitkommaarithmetik) bilden die Gleitkommazahlen eine endliche Arithmetik, die vor allem im Hinblick auf numerische Berechnungen mit (binären) Rechnern entwickelt wurde. ⓘ
Überblick
In Gleitkommasystemen ist der Exponent eine Zahl mit Vorzeichen. Das macht die Implementierung einer zusätzlichen ganzzahligen Arithmetik mit Vorzeichen für Exponentenberechnungen erforderlich. Dieser zusätzliche Aufwand kann vermieden werden, wenn zum Exponenten eine feste Zahl , der Biaswert oder Exzess, addiert wird und statt des Exponenten die Summe gespeichert wird. Diese Summe ist dann eine vorzeichenfreie positive Zahl. Meistens wird die Verwendung eines Bias mit der Darstellung der 0 durch kombiniert. ⓘ
Eine heute selten anzutreffende Alternative ist die Darstellung des Exponenten im Zweierkomplement, im Einerkomplement oder als Betrags-Vorzeichenzahl. ⓘ
Der Vorteil der Biased-Darstellung besteht darin, dass auf diese Weise ein Größenvergleich zwischen zwei positiven Gleitkommazahlen erleichtert wird. Es genügt, die Ziffernfolgen em, also jeweils Exponent e gefolgt von Mantisse m, lexikografisch miteinander zu vergleichen. Eine Gleitkomma-Subtraktion mit anschließendem Vergleich auf Null wäre weitaus aufwändiger. Der Nachteil der Biased-Darstellung gegenüber der Zweierkomplement-Darstellung besteht darin, dass nach einer Addition zweier Biased-Exponenten der Bias subtrahiert werden muss, um das richtige Ergebnis zu erhalten. ⓘ
IEEE 754 verwendet die Darstellung mit B=127 bei Single und B=1023 bei Double. ⓘ
Fließkommazahlen
Eine Zahlendarstellung gibt an, wie eine Zahl kodiert wird, in der Regel als eine Kette von Ziffern. ⓘ
Es gibt verschiedene Mechanismen, mit denen Ziffernfolgen Zahlen darstellen können. In der gebräuchlichen mathematischen Notation kann die Ziffernfolge beliebig lang sein, und die Position des Radixpunkts wird durch ein explizites "Punkt"-Zeichen (Punkt oder Komma) angegeben. Wird der Radixpunkt nicht angegeben, so stellt die Zeichenkette implizit eine ganze Zahl dar, und der nicht angegebene Radixpunkt befindet sich am rechten Ende der Zeichenkette, neben der niedrigstwertigen Ziffer. In Festkommasystemen wird eine Position in der Zeichenkette für den Radixpunkt angegeben. Ein Festkommasystem könnte also eine Zeichenkette mit 8 Dezimalstellen und dem Dezimalpunkt in der Mitte verwenden, wobei "00012345" für 0001,2345 stehen würde. ⓘ
In der wissenschaftlichen Notation wird die angegebene Zahl mit einer Potenz von 10 skaliert, so dass sie in einem bestimmten Bereich liegt - in der Regel zwischen 1 und 10, wobei der Radixpunkt unmittelbar nach der ersten Ziffer erscheint. Der Skalierungsfaktor als Zehnerpotenz wird dann separat am Ende der Zahl angegeben. Die Umlaufzeit des Jupitermondes Io beträgt beispielsweise 152.853,5047 Sekunden, ein Wert, der in wissenschaftlicher Standardnotation als 1,528535047×105 Sekunden dargestellt würde. ⓘ
Die Fließkommadarstellung ist vom Konzept her ähnlich wie die wissenschaftliche Notation. Logisch gesehen besteht eine Fließkommazahl aus:
- Einer vorzeichenbehafteten (d. h. positiven oder negativen) Ziffernfolge mit einer bestimmten Länge und einer bestimmten Basis (oder Radix). Diese Ziffernfolge wird als Signifikant, Mantisse oder Koeffizient bezeichnet. Die Länge des Signifikanten bestimmt die Genauigkeit, mit der Zahlen dargestellt werden können. Es wird davon ausgegangen, dass die Position des Radixpunktes immer irgendwo innerhalb des Signifikanten liegt - oft kurz nach oder kurz vor der höchstwertigen Ziffer oder rechts von der rechtesten (niedrigstwertigen) Ziffer. In diesem Artikel wird im Allgemeinen die Konvention befolgt, dass der Radixpunkt direkt nach der höchstwertigen (linken) Ziffer gesetzt wird.
- Ein vorzeichenbehafteter ganzzahliger Exponent (auch als Charakteristikum oder Skala bezeichnet), der den Betrag der Zahl modifiziert. ⓘ
Um den Wert der Gleitkommazahl zu ermitteln, wird der Signifikant mit der Basis multipliziert, die mit dem Exponenten potenziert wird. Dies entspricht einer Verschiebung des Radixpunkts von seiner impliziten Position um eine Anzahl von Stellen, die dem Wert des Exponenten entspricht - nach rechts, wenn der Exponent positiv ist, oder nach links, wenn der Exponent negativ ist. ⓘ
Zur Basis 10 (der bekannten Dezimalschreibweise) wird beispielsweise die Zahl 152.853,5047, die eine Genauigkeit von zehn Dezimalstellen hat, als Signifikant 1.528.535.047 und Exponent 5 dargestellt. Um den tatsächlichen Wert zu ermitteln, wird nach der ersten Ziffer des Signifikanten ein Dezimalpunkt gesetzt und das Ergebnis mit 105 multipliziert, was 1,528535047×105 oder 152.853,5047 ergibt. Bei der Speicherung einer solchen Zahl muss die Basis (10) nicht gespeichert werden, da sie für den gesamten Bereich der unterstützten Zahlen gleich ist und somit abgeleitet werden kann. ⓘ
Symbolisch gesehen ist dieser Endwert:
Dabei ist s der Signifikant (ohne Berücksichtigung des Dezimalpunkts), p die Genauigkeit (die Anzahl der Ziffern im Signifikanten), b die Basis (in unserem Beispiel die Zahl 10) und e der Exponent. ⓘ
In der Vergangenheit wurden verschiedene Zahlenbasen für die Darstellung von Fließkommazahlen verwendet, wobei die Basis zwei (binär) die gebräuchlichste ist, gefolgt von der Basis zehn (dezimale Fließkommazahl) und anderen, weniger gebräuchlichen Varianten wie Basis sechzehn (hexadezimale Fließkommazahl), Basis acht (oktale Fließkommazahl), Basis vier (quaternäre Fließkommazahl), Basis drei (ausgeglichene ternäre Fließkommazahl) und sogar Basis 256 und Basis 65.536. ⓘ
Eine Gleitkommazahl ist eine rationale Zahl, da sie als eine ganze Zahl geteilt durch eine andere dargestellt werden kann; zum Beispiel ist 1,45×103 (145/100)×1000 oder 145.000/100. Die Basis bestimmt, welche Brüche dargestellt werden können. So kann 1/5 nicht genau als Gleitkommazahl mit einer binären Basis dargestellt werden, aber 1/5 kann genau mit einer dezimalen Basis (0,2 oder 2×10-1) dargestellt werden. 1/3 hingegen kann weder binär (0,010101...) noch dezimal (0,333...) exakt dargestellt werden, aber zur Basis 3 ist es trivial (0,1 oder 1×3-1). Die Fälle, in denen unendliche Ausdehnungen auftreten, hängen von der Basis und ihren Primfaktoren ab. ⓘ
Die Art und Weise, wie der Signifikant (einschließlich seines Vorzeichens) und der Exponent in einem Computer gespeichert werden, hängt von der Implementierung ab. Die gebräuchlichen IEEE-Formate werden später und an anderer Stelle ausführlich beschrieben, aber als Beispiel sei hier die binäre, einfach genaue (32-Bit-)Gleitkommadarstellung genannt, und der Signifikant ist also eine Kette von 24 Bits. Die ersten 33 Bits der Zahl π sind zum Beispiel:
In dieser binären Erweiterung bezeichnen wir die Positionen von 0 (ganz linkes Bit bzw. höchstwertiges Bit) bis 32 (ganz rechtes Bit). Der 24-Bit-Signifikant endet an der Position 23, die oben als das unterstrichene Bit 0 dargestellt ist. Das nächste Bit an Position 24 wird als Rundungsbit bezeichnet. Es wird verwendet, um die 33-Bit-Approximation auf die nächste 24-Bit-Zahl zu runden (für Halbwertszeiten gibt es spezielle Regeln, was hier nicht der Fall ist). Dieses Bit, das in diesem Beispiel 1 ist, wird zu der Ganzzahl addiert, die durch die 24 Bits ganz links gebildet wird:
Wenn dies im Speicher unter Verwendung der IEEE-754-Kodierung gespeichert wird, wird es zum Signifikanten s. Beim Signifikanten wird davon ausgegangen, dass er einen binären Punkt rechts vom ganz linken Bit hat. Die binäre Darstellung von π wird also wie folgt von links nach rechts berechnet:
Dabei ist p die Genauigkeit (24 in diesem Beispiel), n die Position des Bits des Signifikanten von links (hier beginnend bei 0 und endend bei 23) und e der Exponent (1 in diesem Beispiel). ⓘ
Es kann verlangt werden, dass die höchstwertige Stelle des Signifikanten einer Zahl, die nicht Null ist, nicht Null ist (es sei denn, der entsprechende Exponent wäre kleiner als der Mindestwert). Dieser Vorgang wird als Normalisierung bezeichnet. Bei Binärformaten (die nur die Ziffern 0 und 1 verwenden) ist diese von Null verschiedene Ziffer notwendigerweise 1. Daher muss sie nicht im Speicher dargestellt werden, wodurch das Format ein Bit mehr an Präzision erhält. Diese Regel wird auch als führende Bitkonvention, implizite Bitkonvention, versteckte Bitkonvention oder angenommene Bitkonvention bezeichnet. ⓘ
Alternativen zu Fließkommazahlen
Die Gleitkommadarstellung ist bei weitem die gebräuchlichste Methode, um in Computern eine Annäherung an reelle Zahlen darzustellen. Es gibt jedoch auch Alternativen:
- Bei der Festkommadarstellung werden ganzzahlige Hardware-Operationen verwendet, die durch eine Software-Implementierung einer bestimmten Konvention über die Position des Binär- oder Dezimalpunkts gesteuert werden, z. B. 6 Bits oder Ziffern von rechts. Die Hardware zur Bearbeitung dieser Darstellungen ist weniger kostspielig als die Fließkommadarstellung und kann auch zur Durchführung normaler Ganzzahloperationen verwendet werden. Die binäre Festkommadarstellung wird in der Regel in speziellen Anwendungen auf eingebetteten Prozessoren verwendet, die nur ganzzahlige Arithmetik ausführen können, während die dezimale Festkommadarstellung in kommerziellen Anwendungen üblich ist.
- Logarithmische Zahlensysteme (LNS) stellen eine reelle Zahl durch den Logarithmus ihres Absolutwerts und ein Vorzeichenbit dar. Die Werteverteilung ist ähnlich wie bei der Fließkommazahl, aber die Wert-zu-Darstellung-Kurve (d. h. der Graph der Logarithmusfunktion) ist glatt (außer bei 0). Im Gegensatz zur Fließkommaarithmetik sind in einem logarithmischen Zahlensystem Multiplikation, Division und Potenzierung einfach zu implementieren, Addition und Subtraktion sind jedoch komplex. Die (symmetrische) Level-Index-Arithmetik (LI und SLI) von Charles Clenshaw, Frank Olver und Peter Turner ist ein Schema, das auf einer verallgemeinerten Logarithmendarstellung beruht.
- Tapered floating-point representation, die in der Praxis nicht verwendet zu werden scheint.
- Einige einfache rationale Zahlen (z. B. 1/3 und 1/10) können nicht exakt in binärer Gleitkommadarstellung dargestellt werden, egal wie hoch die Genauigkeit ist. Die Verwendung einer anderen Radix erlaubt es, einige von ihnen darzustellen (z. B. 1/10 in dezimaler Fließkommazahl), aber die Möglichkeiten bleiben begrenzt. Softwarepakete, die rationale Arithmetik durchführen, stellen Zahlen als Brüche mit ganzzahligem Zähler und Nenner dar und können daher jede rationale Zahl exakt darstellen. Solche Pakete müssen im Allgemeinen "Bignum"-Arithmetik für die einzelnen ganzen Zahlen verwenden.
- Die Intervallarithmetik ermöglicht es, Zahlen als Intervalle darzustellen und garantierte Grenzen für die Ergebnisse zu erhalten. Sie basiert im Allgemeinen auf anderen Arithmetiken, insbesondere der Gleitkommaarithmetik.
- Computeralgebra-Systeme wie Mathematica, Maxima und Maple können oft mit irrationalen Zahlen wie oder auf eine völlig "formale" Weise behandeln, ohne sich mit einer spezifischen Kodierung des Signifikanten zu befassen. Ein solches Programm kann Ausdrücke wie "" genau auswerten, da es so programmiert ist, dass es die zugrunde liegende Mathematik direkt verarbeitet, anstatt für jede Zwischenberechnung Näherungswerte zu verwenden. ⓘ
Geschichte
1914 schlug Leonardo Torres y Quevedo eine Form der Fließkommazahl vor, als er seinen Entwurf für eine elektromechanische Spezialrechenmaschine diskutierte. Im Jahr 1938 stellte Konrad Zuse aus Berlin die Z1 fertig, den ersten binären, programmierbaren mechanischen Rechner; er verwendet eine binäre 24-Bit-Gleitkommazahlendarstellung mit einem 7-Bit-Exponenten mit Vorzeichen, einem 17-Bit-Signifikanten (einschließlich eines impliziten Bits) und einem Vorzeichenbit. Die zuverlässigere Z3 auf Relaisbasis, die 1941 fertiggestellt wurde, verfügt über Darstellungen für positive und negative Unendlichkeiten; insbesondere implementiert sie definierte Operationen mit Unendlichkeit, wie z. B. und bleibt bei undefinierten Operationen stehen, wie z. B. . ⓘ
Zuse schlug auch eine sorgfältig gerundete Gleitkomma-Arithmetik vor, die jedoch nicht fertiggestellt wurde, und die und NaN-Darstellungen, die die Merkmale des IEEE-Standards um vier Jahrzehnte vorwegnahmen. Im Gegensatz dazu empfahl von Neumann für die IAS-Maschine von 1951 keine Fließkommazahlen, da er die Festkomma-Arithmetik für besser hielt. ⓘ
Der erste kommerzielle Computer mit Fließkomma-Hardware war der Z4-Computer von Zuse, der in den Jahren 1942-1945 entwickelt wurde. Im Jahr 1946 stellten die Bell Laboratories den Mark V vor, der dezimale Gleitkommazahlen implementierte. ⓘ
Der Pilot ACE verfügt über binäre Fließkomma-Arithmetik und wurde 1950 im National Physical Laboratory, Großbritannien, in Betrieb genommen. Dreiunddreißig davon wurden später als English Electric DEUCE in den Handel gebracht. Die Arithmetik ist zwar in Software implementiert, aber mit einer Taktrate von einem Megahertz war die Geschwindigkeit der Gleitkomma- und Festkommaoperationen in dieser Maschine anfangs schneller als bei vielen konkurrierenden Computern. ⓘ
Im Jahr 1954 folgte die Massenproduktion der IBM 704, mit der die Verwendung eines voreingenommenen Exponenten eingeführt wurde. Viele Jahrzehnte lang war die Fließkomma-Hardware in der Regel ein optionales Merkmal, und Computer, die damit ausgestattet waren, wurden als "wissenschaftliche Computer" oder als Computer mit der Fähigkeit zum "wissenschaftlichen Rechnen" (SC) bezeichnet (siehe auch Erweiterungen für wissenschaftliches Rechnen (XSC)). Erst mit der Einführung des Intel i486 im Jahr 1989 wurde die Fließkommafähigkeit von Allzweck-Personalcomputern als Standardmerkmal in die Hardware integriert. ⓘ
Die UNIVAC 1100/2200-Serie, die 1962 eingeführt wurde, unterstützte zwei Gleitkommadarstellungen:
- Einfache Genauigkeit: 36 Bits, organisiert als 1-Bit-Vorzeichen, ein 8-Bit-Exponent und ein 27-Bit-Signifikant.
- Doppelte Genauigkeit: 72 Bits, organisiert als 1-Bit-Vorzeichen, ein 11-Bit-Exponent und ein 60-Bit-Signifikant. ⓘ
Der IBM 7094, der ebenfalls 1962 auf den Markt kam, unterstützte Darstellungen mit einfacher und doppelter Genauigkeit, hatte aber keinen Bezug zu den Darstellungen des UNIVAC. Tatsächlich führte IBM 1964 hexadezimale Gleitkommadarstellungen in seinen System/360-Großrechnern ein; dieselben Darstellungen sind auch heute noch in modernen Systemen mit z/Architektur verfügbar. Im Jahr 1998 implementierte IBM die IEEE-kompatible binäre Gleitkomma-Arithmetik in seine Mainframes; 2005 fügte IBM auch die IEEE-kompatible dezimale Gleitkomma-Arithmetik hinzu. ⓘ
Ursprünglich verwendeten die Computer viele verschiedene Darstellungen für Gleitkommazahlen. Die fehlende Standardisierung auf Großrechnerebene war Anfang der 1970er Jahre ein ständiges Problem für diejenigen, die Quellcode auf höherer Ebene schrieben und pflegten; diese Gleitkommastandards der Hersteller unterschieden sich in den Wortgrößen, den Darstellungen, dem Rundungsverhalten und der allgemeinen Genauigkeit der Operationen. Die Kompatibilität von Fließkommazahlen über mehrere Computersysteme hinweg bedurfte Anfang der 1980er Jahre dringend einer Standardisierung, was zur Schaffung des IEEE-754-Standards führte, nachdem das 32-Bit- (bzw. 64-Bit-) Wort alltäglich geworden war. Dieser Standard basierte maßgeblich auf einem Vorschlag von Intel, das den numerischen Coprozessor i8087 entwickelte; Motorola, das zur gleichen Zeit den 68000 entwickelte, leistete ebenfalls einen wichtigen Beitrag. ⓘ
1989 wurde der Mathematiker und Informatiker William Kahan mit dem Turing Award ausgezeichnet, weil er der Hauptverantwortliche für diesen Vorschlag war; unterstützt wurde er von seinem Studenten (Jerome Coonen) und einem Gastprofessor (Harold Stone). ⓘ
Zu den x86-Innovationen gehören folgende:
- Eine genau spezifizierte Gleitkommadarstellung auf Bitstring-Ebene, so dass alle kompatiblen Computer Bitmuster auf dieselbe Weise interpretieren. Dies ermöglicht eine genaue und effiziente Übertragung von Fließkommazahlen von einem Computer zum anderen (nach Berücksichtigung der Endianness).
- Ein genau spezifiziertes Verhalten für die arithmetischen Operationen: Das Ergebnis muss so aussehen, als ob unendlich präzise arithmetisch gerechnet würde, um einen Wert zu erhalten, der dann nach bestimmten Regeln gerundet wird. Dies bedeutet, dass ein konformes Computerprogramm bei einer bestimmten Eingabe immer das gleiche Ergebnis liefert, wodurch der fast mystische Ruf der Fließkommaberechnung wegen ihres bis dahin scheinbar nicht-deterministischen Verhaltens gemildert wird.
- Die Fähigkeit, außergewöhnliche Bedingungen (Überlauf, Teilung durch Null usw.) auf unbedenkliche Weise durch eine Berechnung weiterzuleiten und dann von der Software auf kontrollierte Weise behandelt zu werden. ⓘ
Die erste dokumentierte Verwendung der Gleitkommaschreibweise liegt etwa 2700 Jahre zurück: Im Zweistromland (Mesopotamien) wurden wissenschaftliche Rechnungen mit der Basis durchgeführt und der Exponent (eine meistens kleine ganze Zahl) einfach im Kopf mitgeführt. Dasselbe Vorgehen war bis vor kurzer Zeit bei Berechnungen mit einem Rechenschieber üblich. ⓘ
Bereich der Fließkommazahlen
Eine Fließkommazahl besteht aus zwei Festkomma-Komponenten, deren Bereich ausschließlich von der Anzahl der Bits oder Ziffern in ihrer Darstellung abhängt. Während die Komponenten linear von ihrem Bereich abhängen, hängt der Bereich der Fließkommazahlen linear vom Bereich des Signifikanten und exponentiell vom Bereich des Exponenten ab, der der Zahl einen besonders großen Bereich zuweist. ⓘ
Auf einem typischen Computersystem hat eine binäre Gleitkommazahl mit doppelter Genauigkeit (64 Bit) einen Koeffizienten von 53 Bit (einschließlich 1 impliziertem Bit), einen Exponenten von 11 Bit und 1 Vorzeichenbit. Da 210 = 1024 ist, reicht der gesamte Bereich der positiven normalen Gleitkommazahlen in diesem Format von 2-1022 ≈ 2 × 10-308 bis etwa 21024 ≈ 2 × 10308. ⓘ
Die Anzahl der normierten Gleitkommazahlen in einem System (B, P, L, U), wobei
- B ist die Basis des Systems,
- P ist die Genauigkeit des Signifikanten (zur Basis B),
- L ist der kleinste Exponent des Systems,
- U ist der größte Exponent des Systems,
ist . ⓘ
Es gibt eine kleinste positive normalisierte Gleitkommazahl,
- Unterlaufpegel = UFL = , ⓘ
die eine 1 als führende Ziffer und 0 für die übrigen Ziffern des Signifikanten und den kleinstmöglichen Wert für den Exponenten hat. ⓘ
Es gibt eine größte Gleitkommazahl,
- Überlaufpegel = OFL = , ⓘ
die B - 1 als Wert für jede Stelle des Signifikanten und den größtmöglichen Wert für den Exponenten hat. ⓘ
Darüber hinaus gibt es darstellbare Werte, die genau zwischen -UFL und UFL liegen. Das sind positive und negative Nullen sowie denormalisierte Zahlen. ⓘ
Beispiel: Bei IEEE-754-Zahlen vom Typ Single mit der Basis ist der kleinste mögliche Exponent −126 und der größte 127. Damit ist die größte in diesem System darstellbare Gleitkommazahl und die kleinste positive normalisierte Gleitkommazahl . Diese Größen, und , beschreiben den zulässigen Wertebereich. ⓘ
IEEE 754: Fließkommazahlen in modernen Computern
Fließkomma-Formate ⓘ |
---|
IEEE 754 |
|
Andere |
|
Die IEEE standardisierte 1985 die Computerdarstellung für binäre Gleitkommazahlen in IEEE 754 (auch bekannt als IEC 60559). Diese erste Norm wird von fast allen modernen Computern befolgt. Er wurde im Jahr 2008 überarbeitet. IBM-Mainframes unterstützen neben dem binären IEEE-754-Format auch das IBM-eigene hexadezimale Gleitkomma-Format und das dezimale IEEE-754-2008-Gleitkomma-Format. Die Cray T90-Serie verfügte über eine IEEE-Version, aber der SV1 verwendet weiterhin das Cray-Gleitkommaformat. ⓘ
Die Norm sieht viele eng verwandte Formate vor, die sich nur in wenigen Details unterscheiden. Fünf dieser Formate werden als Basisformate bezeichnet, andere als erweiterte Präzisionsformate und erweiterbare Präzisionsformate. Drei Formate sind in der Computerhardware und in Sprachen besonders weit verbreitet:
- Einfache Genauigkeit (binary32), die in der Regel zur Darstellung des Typs "float" in der Sprachfamilie C verwendet wird. Es handelt sich um ein Binärformat, das 32 Bits (4 Bytes) belegt und dessen Signifikant eine Genauigkeit von 24 Bits (etwa 7 Dezimalstellen) hat.
- Doppelte Genauigkeit (binary64), wird normalerweise verwendet, um den Typ "double" in der C-Sprachfamilie darzustellen. Es handelt sich um ein Binärformat, das 64 Bits (8 Bytes) belegt und dessen Signifikant eine Genauigkeit von 53 Bits (ca. 16 Dezimalstellen) hat.
- Double extended, auch zweideutig als "extended precision"-Format bezeichnet. Hierbei handelt es sich um ein Binärformat, das mindestens 79 Bits belegt (80, wenn die Hidden/Implicit-Bit-Regel nicht verwendet wird) und dessen Signifikant eine Genauigkeit von mindestens 64 Bits (etwa 19 Dezimalstellen) hat. Die C99- und C11-Normen der C-Sprachfamilie empfehlen in ihrem Anhang F ("IEC 60559 floating-point arithmetic"), ein solches erweitertes Format als "long double" zur Verfügung zu stellen. Ein Format, das die minimalen Anforderungen erfüllt (64-Bit-Signifikantenpräzision, 15-Bit-Exponent, also passend zu 80 Bit), wird von der x86-Architektur bereitgestellt. Auf solchen Prozessoren kann dieses Format oft mit "long double" verwendet werden, obwohl die erweiterte Genauigkeit mit MSVC nicht verfügbar ist. Zu Ausrichtungszwecken speichern viele Tools diesen 80-Bit-Wert in einem 96-Bit- oder 128-Bit-Raum. Auf anderen Prozessoren kann "long double" für ein größeres Format stehen, wie z. B. vierfache Genauigkeit oder einfach doppelte Genauigkeit, wenn keine Form der erweiterten Genauigkeit verfügbar ist. ⓘ
Durch die Erhöhung der Genauigkeit der Gleitkommadarstellung wird im Allgemeinen der durch Zwischenberechnungen verursachte Rundungsfehler verringert. Zu den weniger verbreiteten IEEE-Formaten gehören:
- Vierfache Genauigkeit (binary128). Dies ist ein Binärformat, das 128 Bits (16 Bytes) belegt und dessen Signifikant eine Genauigkeit von 113 Bits (etwa 34 Dezimalstellen) hat.
- Dezimal64 und Dezimal128 Gleitkommaformate. Diese Formate sind zusammen mit dem decimal32-Format für die korrekte Durchführung der Dezimalrundung vorgesehen.
- Halbe Genauigkeit, auch binary16 genannt, eine 16-Bit-Gleitkommazahl. Es wird in der NVIDIA Cg-Grafiksprache und im openEXR-Standard verwendet. ⓘ
Jede ganze Zahl mit einem Absolutwert kleiner als 224 kann im einfachgenauen Format exakt dargestellt werden, und jede ganze Zahl mit einem Absolutwert kleiner als 253 kann im doppeltgenauen Format exakt dargestellt werden. Darüber hinaus kann ein breiter Bereich von Potenzen des 2-fachen einer solchen Zahl dargestellt werden. Diese Eigenschaften werden manchmal für rein ganzzahlige Daten verwendet, um 53-Bit-Ganzzahlen auf Plattformen zu erhalten, die über doppeltgenaue Gleitkommazahlen, aber nur 32-Bit-Ganzzahlen verfügen. ⓘ
Die Norm legt einige besondere Werte und ihre Darstellung fest: positive Unendlichkeit (+∞), negative Unendlichkeit (-∞), eine negative Null (-0), die sich von der gewöhnlichen ("positiven") Null unterscheidet, und "keine Zahl"-Werte (NaNs). ⓘ
Der Vergleich von Fließkommazahlen, wie er in der IEEE-Norm definiert ist, unterscheidet sich ein wenig vom üblichen Ganzzahlvergleich. Negative und positive Nullen werden gleich verglichen, und jedes NaN ist ungleich zu jedem Wert, einschließlich sich selbst. Alle endlichen Fließkommazahlen sind streng kleiner als +∞ und streng größer als -∞, und sie sind in der gleichen Weise geordnet wie ihre Werte (in der Menge der reellen Zahlen). ⓘ
Interne Darstellung
Fließkommazahlen werden in der Regel in Form des Vorzeichenbits, des Exponenten und des Signifikanten oder der Mantisse (von links nach rechts) in ein Computerdatum gepackt. Für die IEEE-754-Binärformate (basic und extended), für die es bereits Hardware-Implementierungen gibt, werden sie wie folgt aufgeteilt:
Typ | Vorzeichen | Exponent | Signifikantenfeld | Bits insgesamt | Vorspannung des Exponenten | Bits Genauigkeit | Anzahl der Dezimalziffern ⓘ | |
---|---|---|---|---|---|---|---|---|
Halb (IEEE 754-2008) | 1 | 5 | 10 | 16 | 15 | 11 | ~3.3 | |
Einfach | 1 | 8 | 23 | 32 | 127 | 24 | ~7.2 | |
Doppelt | 1 | 11 | 52 | 64 | 1023 | 53 | ~15.9 | |
x86 erweiterte Genauigkeit | 1 | 15 | 64 | 80 | 16383 | 64 | ~19.2 | |
Vierfach | 1 | 15 | 112 | 128 | 16383 | 113 | ~34.0 |
Während der Exponent positiv oder negativ sein kann, wird er in Binärformaten als vorzeichenlose Zahl gespeichert, zu der ein fester "Bias" hinzugefügt wird. Alle 0-Werte in diesem Feld sind für Nullen und subnormale Zahlen reserviert; alle 1-Werte sind für Unendlichkeiten und NaN reserviert. Der Exponentenbereich für normalisierte Zahlen ist [-126, 127] für einfache Genauigkeit, [-1022, 1023] für doppelte oder [-16382, 16383] für vierfache Genauigkeit. Normalisierte Zahlen schließen subnormale Werte, Nullen, Unendlichkeiten und NaNs aus. ⓘ
In den IEEE-Binäraustauschformaten wird das führende 1-Bit eines normalisierten Signifikanten nicht in den Computerdaten gespeichert. Man nennt es das "versteckte" oder "implizite" Bit. Aus diesem Grund hat das Einfachpräzisionsformat ein Signifikand mit einer Genauigkeit von 24 Bits, das Doppelpräzisionsformat hat 53 Bits und das Vierfachformat hat 113 Bits. ⓘ
Zum Beispiel wurde oben gezeigt, dass π, gerundet auf 24 Bits Genauigkeit, folgende Werte hat:
- Vorzeichen = 0 ; e = 1 ; s = 110010010000111111011011 (einschließlich des versteckten Bits)
Die Summe des Exponenten Bias (127) und des Exponenten (1) ist 128, so dass dies im einfach präzisen Format dargestellt wird als
- 0 10000000 10010010000111111011011 (ohne das versteckte Bit) = 40490FDB als Hexadezimalzahl. ⓘ
Ein Beispiel für ein Layout für 32-Bit-Gleitkommazahlen ist ⓘ
und das 64-Bit-Layout ist ähnlich. ⓘ
Besondere Werte
Null mit Vorzeichen
In der Norm IEEE 754 ist die Null vorzeichenbehaftet, was bedeutet, dass es sowohl eine "positive Null" (+0) als auch eine "negative Null" (-0) gibt. In den meisten Laufzeitumgebungen wird die positive Null normalerweise als "0
" und die negative Null als "-0" ausgegeben. Die beiden Werte verhalten sich bei numerischen Vergleichen gleich, aber einige Operationen liefern für +0 und -0 unterschiedliche Ergebnisse. 1/(-0) liefert beispielsweise negative Unendlichkeit, während 1/+0 positive Unendlichkeit liefert (so dass die Identität 1/(1/±∞) = ±∞ erhalten bleibt). Andere gebräuchliche Funktionen mit einer Unstetigkeit bei x=0, die +0 und -0 unterschiedlich behandeln können, sind log(x), signum(x) und die Hauptquadratwurzel von y + xi für jede negative Zahl y. Wie bei jedem Näherungsschema können Operationen mit "negativer Null" gelegentlich Verwirrung stiften. Zum Beispiel bedeutet in IEEE 754 x = y nicht immer 1/x = 1/y, da 0 = -0, sondern 1/0 ≠ 1/-0. ⓘ
Subnormale Zahlen
Subnormale Werte füllen die Unterlauflücke mit Werten, bei denen der absolute Abstand zwischen ihnen derselbe ist wie bei benachbarten Werten knapp außerhalb der Unterlauflücke. Dies ist eine Verbesserung gegenüber der älteren Praxis, bei der nur Null in der Unterlauflücke stand und die Unterlaufergebnisse durch Null ersetzt wurden (flush to zero). ⓘ
Moderne Fließkomma-Hardware verarbeitet in der Regel subnormale Werte (ebenso wie normale Werte) und erfordert keine Software-Emulation für subnormale Werte. ⓘ
Unendlichkeiten
Die Unendlichkeiten der erweiterten reellen Zahlenreihe können in IEEE-Gleitkomma-Datentypen dargestellt werden, genau wie gewöhnliche Gleitkomma-Werte wie 1, 1,5, usw. Sie sind in keiner Weise Fehlerwerte, obwohl sie oft (je nach Rundung) als Ersatzwerte bei einem Überlauf verwendet werden. Bei einer Divide-by-Zero-Ausnahme wird eine positive oder negative Unendlichkeit als exaktes Ergebnis zurückgegeben. Eine Unendlichkeit kann auch als Zahl eingeführt werden (wie das Makro "INFINITY" in C oder "∞", wenn die Programmiersprache diese Syntax erlaubt). ⓘ
IEEE 754 verlangt, dass Unendlichkeiten in einer vernünftigen Weise gehandhabt werden, z. B.
- (+∞) + (+7) = (+∞)
- (+∞) × (−2) = (−∞)
- (+∞) × 0 = NaN - es gibt nichts Sinnvolles zu tun ⓘ
NaNs
IEEE 754 legt einen speziellen Wert namens "Not a Number" (NaN) fest, der als Ergebnis bestimmter "ungültiger" Operationen zurückgegeben wird, z. B. 0/0, ∞×0 oder sqrt(-1). Im Allgemeinen werden NaNs weitergegeben, d. h. die meisten Operationen, die ein NaN beinhalten, führen zu einem NaN, obwohl Funktionen, die ein bestimmtes Ergebnis für eine beliebige Fließkommazahl liefern würden, dies auch für NaNs tun, z. B. NaN ^ 0 = 1. Es gibt zwei Arten von NaNs: die standardmäßigen stillen NaNs und, optional, signalisierende NaNs. Ein signalisiertes NaN in einer beliebigen arithmetischen Operation (einschließlich numerischer Vergleiche) führt zur Meldung einer Ausnahme "ungültige Operation". ⓘ
Die vom Standard festgelegte Darstellung von NaNs hat einige nicht spezifizierte Bits, die zur Kodierung des Fehlertyps oder der Fehlerquelle verwendet werden könnten; für diese Kodierung gibt es jedoch keinen Standard. Theoretisch könnte die Signalisierung von NaNs von einem Laufzeitsystem verwendet werden, um nicht initialisierte Variablen zu kennzeichnen oder die Fließkommazahlen mit anderen speziellen Werten zu erweitern, ohne die Berechnungen mit normalen Werten zu verlangsamen, obwohl solche Erweiterungen nicht üblich sind. ⓘ
Gründe für den Entwurf von IEEE 754
Es ist ein weit verbreiteter Irrglaube, dass die hier besprochenen, eher esoterischen Merkmale des IEEE 754-Standards, wie erweiterte Formate, NaN, Unendlichkeiten, Subnormale usw., nur für numerische Analytiker oder für fortgeschrittene numerische Anwendungen von Interesse sind. Tatsächlich ist das Gegenteil der Fall: Diese Funktionen sind so konzipiert, dass sie sichere und robuste Vorgaben für numerisch unbedarfte Programmierer bieten und gleichzeitig anspruchsvolle numerische Bibliotheken von Experten unterstützen. Der Hauptentwickler von IEEE 754, William Kahan, merkt an, dass es falsch ist, "... Funktionen des IEEE-Standards 754 für binäre Fließkommaarithmetik, die ... [nicht] geschätzt werden, als Funktionen zu betrachten, die nur von numerischen Experten genutzt werden können. Die Fakten sind genau das Gegenteil. Im Jahr 1977 wurden diese Funktionen in den Intel 8087 eingebaut, um einen möglichst breiten Markt zu bedienen... Die Fehleranalyse zeigt uns, wie wir die Gleitkommaarithmetik, wie die IEEE-Norm 754, so gestalten können, dass sie gegenüber der wohlmeinenden Unwissenheit der Programmierer einigermaßen tolerant ist.
- Die speziellen Werte wie Unendlich und NaN stellen sicher, dass die Fließkomma-Arithmetik algebraisch vollständig ist: Jede Fließkomma-Operation führt zu einem wohldefinierten Ergebnis und löst standardmäßig keine Maschinenunterbrechung oder Traps aus. Darüber hinaus wurde die Auswahl spezieller Werte, die in Ausnahmefällen zurückgegeben werden, so konzipiert, dass in vielen Fällen die richtige Antwort gegeben wird. So ergeben beispielsweise bei der IEEE 754-Arithmetik fortgesetzte Brüche wie R(z) := 7 - 3/[z - 2 - 1/(z - 7 + 10/[z - 2 - 2/(z - 3)])] bei allen Eingaben die richtige Antwort, da die potenzielle Teilung durch Null, z. B. für z = 3, korrekt mit +unendlich gehandhabt wird und solche Ausnahmen daher sicher ignoriert werden können. Wie Kahan feststellte, wäre der unbehandelte Trap in Folge eines Überlaufs bei der Konvertierung von Gleitkomma- in 16-Bit-Ganzzahlen, der den Verlust einer Ariane-5-Rakete verursachte, unter der standardmäßigen IEEE-754-Gleitkomma-Politik nicht aufgetreten.
- Subnormale Zahlen stellen sicher, dass für endliche Gleitkommazahlen x und y x - y = 0 ist, wenn x = y ist, was bei früheren Gleitkommadarstellungen nicht der Fall war.
- Zum Grundgedanken des x87-80-Bit-Formats bemerkt Kahan: "Dieses erweiterte Format ist so konzipiert, dass es mit vernachlässigbarem Geschwindigkeitsverlust für alle außer den einfachsten Arithmetiken mit Fließkomma- und Doppel-Operanden verwendet werden kann. Es sollte zum Beispiel für Scratch-Variablen in Schleifen verwendet werden, die Rekursionen wie Polynomauswertung, Skalarprodukte, partielle und fortgesetzte Brüche implementieren. Sie verhindert häufig einen vorzeitigen Über-/Unterlauf oder eine schwerwiegende lokale Annullierung, die einfache Algorithmen zunichte machen kann. Die Berechnung von Zwischenergebnissen in einem erweiterten Format mit hoher Genauigkeit und erweitertem Exponenten hat Vorläufer in der historischen Praxis des wissenschaftlichen Rechnens und in der Entwicklung wissenschaftlicher Taschenrechner, z. B. führten die Finanzrechner von Hewlett-Packard arithmetische und finanzielle Funktionen mit drei Dezimalstellen mehr aus, als sie speicherten oder anzeigten. Die Implementierung der erweiterten Genauigkeit ermöglichte die einfache Entwicklung von elementaren Standardfunktionsbibliotheken, die normalerweise Ergebnisse mit doppelter Genauigkeit innerhalb einer Einheit an der letzten Stelle (ULP) bei hoher Geschwindigkeit lieferten.
- Die korrekte Rundung von Werten auf den nächsten darstellbaren Wert vermeidet systematische Verzerrungen in Berechnungen und verlangsamt das Wachstum von Fehlern. Das Runden von Gleichständen auf eine gerade Zahl beseitigt die statistische Verzerrung, die beim Addieren ähnlicher Zahlen auftreten kann.
- Die gerichtete Rundung wurde als Hilfsmittel bei der Überprüfung von Fehlergrenzen, z. B. in der Intervallarithmetik, konzipiert. Sie wird auch bei der Implementierung einiger Funktionen verwendet.
- Die mathematische Grundlage der Operationen, insbesondere die korrekte Rundung, ermöglicht es, mathematische Eigenschaften zu beweisen und Fließkomma-Algorithmen wie 2Sum, Fast2Sum und den Kahan-Summationsalgorithmus zu entwerfen, um z. B. die Genauigkeit zu verbessern oder Unterprogramme für die Mehrfachpräzisionsarithmetik relativ einfach zu implementieren. ⓘ
Eine Eigenschaft der einfach- und doppeltgenauen Formate ist, dass ihre Kodierung eine einfache Sortierung ohne Verwendung von Fließkomma-Hardware ermöglicht. Ihre als Zweierkomplement-Ganzzahl interpretierten Bits sortieren bereits die positiven Werte korrekt, wobei die negativen Werte umgekehrt werden. Mit einem xor, das das Vorzeichenbit für positive Werte und alle Bits für negative Werte umkehrt, werden alle Werte als vorzeichenlose Ganzzahlen (mit -0 < +0) sortierbar. Es ist unklar, ob diese Eigenschaft beabsichtigt ist. ⓘ
Andere bemerkenswerte Gleitkommaformate
Neben den weit verbreiteten IEEE-754-Standardformaten werden oder wurden in bestimmten bereichsspezifischen Bereichen auch andere Fließkommaformate verwendet.
- Das Microsoft Binary Format (MBF) wurde für die Microsoft BASIC-Sprachprodukte entwickelt, darunter Microsofts erstes Produkt überhaupt, Altair BASIC (1975), TRS-80 LEVEL II, CP/M's MBASIC, IBM PC 5150's BASICA, MS-DOS's GW-BASIC und QuickBASIC vor Version 4.00. QuickBASIC Version 4.00 und 4.50 wechselte zum IEEE 754-1985 Format, kann aber mit der Befehlsoption /MBF zum MBF-Format zurückkehren. MBF wurde im Frühjahr 1975 von Monte Davidoff, einem Freund von Bill Gates, auf einem simulierten Intel 8080 für den MITS Altair 8800 entworfen und entwickelt. Die erste Version vom Juli 1975 unterstützte aufgrund der Kosten für den 4-Kilobyte-Speicher des MITS Altair 8800 ein Single-Precision-Format (32 Bit). Im Dezember 1975 wurde die 8-Kilobyte-Version um ein Double-Precision-Format (64 Bits) erweitert. Für andere CPUs, insbesondere den MOS 6502 (Apple //, Commodore PET, Atari), Motorola 6800 (MITS Altair 680) und Motorola 6809 (TRS-80 Color Computer), wurde ein einfaches Präzisionsformat (40 Bits) eingeführt. Alle Microsoft-Sprachprodukte von 1975 bis 1987 verwendeten das Microsoft Binary Format, bis Microsoft das IEEE-754-Standardformat in all seinen Produkten ab 1988 bis zu den aktuellen Versionen übernahm. MBF besteht aus dem MBF-Single-Precision-Format (32 Bits, "6-digit BASIC"), dem MBF-Extended-Precision-Format (40 Bits, "9-digit BASIC") und dem MBF-Double-Precision-Format (64 Bits); jedes dieser Formate wird mit einem 8-Bit-Exponenten, gefolgt von einem Vorzeichenbit und einem Signifikanten von 23, 31 bzw. 55 Bits dargestellt.
- Das Bfloat16-Format benötigt die gleiche Speichermenge (16 Bits) wie das IEEE-754-Halbpräzisionsformat, weist dem Exponenten jedoch 8 Bits statt 5 zu und bietet damit den gleichen Bereich wie eine IEEE-754-Zahl mit einfacher Genauigkeit. Der Preis dafür ist eine geringere Genauigkeit, da das Feld für den hinteren Signifikanten von 10 auf 7 Bits reduziert wird. Dieses Format wird vor allem beim Training von Modellen für maschinelles Lernen verwendet, bei denen der Bereich wichtiger ist als die Genauigkeit. Viele Beschleuniger für maschinelles Lernen bieten Hardware-Unterstützung für dieses Format.
- Das TensorFloat-32-Format kombiniert die 8 Bits des Exponenten von Bfloat16 mit den 10 Bits des hinteren Signifikantenfeldes von Halbpräzisionsformaten, was zu einer Größe von 19 Bits führt. Dieses Format wurde von Nvidia eingeführt, das in den Tensor Cores seiner GPUs, die auf der Nvidia Ampere Architektur basieren, Hardwareunterstützung dafür bietet. Der Nachteil dieses Formats ist seine Größe, die keine Potenz von 2 ist. Laut Nvidia sollte dieses Format jedoch nur intern von der Hardware verwendet werden, um Berechnungen zu beschleunigen, während Eingaben und Ausgaben im 32-Bit IEEE 754-Format mit einfacher Genauigkeit gespeichert werden sollten.
- Die GPUs der Hopper-Architektur bieten zwei FP8-Formate: eines mit demselben numerischen Bereich wie Halbpräzision (E5M2) und eines mit höherer Präzision, aber geringerem Bereich (E4M3). ⓘ
Die Spezifikationen von +Bfloat16, TensorFloat-32 und den beiden FP8-Formaten im Vergleich zu den IEEE-754-Standardformaten mit halber Genauigkeit und einfacher Genauigkeit | Typ | Vorzeichen | Exponent | Nachgestelltes Signifikantenfeld | Bits insgesamt ⓘ |
---|---|---|---|---|---|
FP8 (E4M3) | 1 | 4 | 3 | 8 | |
FP8 (E5M2) | 1 | 5 | 2 | 8 | |
Halbpräzision | 1 | 5 | 10 | 16 | |
Bfloat16 | 1 | 8 | 7 | 16 | |
TensorFloat-32 | 1 | 8 | 10 | 19 | |
Einfachpräzise | 1 | 8 | 23 | 32 |
Darstellbare Zahlen, Konvertierung und Rundung
Alle im Fließkommaformat ausgedrückten Zahlen sind von Natur aus rationale Zahlen mit einer abschließenden Erweiterung in der entsprechenden Basis (z. B. eine abschließende Dezimal-Erweiterung zur Basis 10 oder eine abschließende Binär-Erweiterung zur Basis 2). Irrationale Zahlen, wie z. B. π oder √2, oder nicht terminierende rationale Zahlen, müssen approximiert werden. Die Anzahl der Ziffern (oder Bits) der Genauigkeit schränkt auch die Menge der rationalen Zahlen ein, die exakt dargestellt werden können. So kann beispielsweise die Dezimalzahl 123456789 nicht exakt dargestellt werden, wenn nur acht Dezimalstellen zur Verfügung stehen (sie würde auf einen der beiden darstellbaren Werte gerundet, 12345678 × 101 oder 12345679 × 101); dasselbe gilt für nicht endliche Ziffern (.5, die entweder auf .55555555 oder .55555556 gerundet wird). ⓘ
Wenn eine Zahl in einem Format dargestellt wird (z. B. als Zeichenkette), das keine native Gleitkommadarstellung ist, die von einer Computerimplementierung unterstützt wird, muss sie umgewandelt werden, bevor sie in dieser Implementierung verwendet werden kann. Wenn die Zahl exakt im Fließkommaformat dargestellt werden kann, ist die Umwandlung exakt. Wenn es keine exakte Darstellung gibt, muss bei der Konvertierung entschieden werden, welche Fließkommazahl zur Darstellung des ursprünglichen Wertes verwendet werden soll. Die gewählte Darstellung hat einen anderen Wert als das Original, und der so angepasste Wert wird als gerundeter Wert bezeichnet. ⓘ
Ob eine rationale Zahl eine abschließende Erweiterung hat oder nicht, hängt von der Basis ab. In der Basis 10 hat zum Beispiel die Zahl 1/2 eine endliche Erweiterung (0,5), während die Zahl 1/3 keine hat (0,333...). In der Basis 2 sind nur rationale Zahlen mit Nennern, die Potenzen von 2 sind (wie 1/2 oder 3/16), terminierend. Jede rationale Zahl mit einem Nenner, der einen anderen Primfaktor als 2 hat, hat eine unendliche binäre Erweiterung. Das bedeutet, dass Zahlen, die im Dezimalformat kurz und exakt erscheinen, bei der Umwandlung in binäre Fließkommazahlen möglicherweise angenähert werden müssen. Die Dezimalzahl 0,1 lässt sich beispielsweise nicht in binärer Fließkommazahl mit endlicher Genauigkeit darstellen; die exakte binäre Darstellung würde eine "1100"-Folge ergeben, die sich endlos fortsetzt:
- e = -4; s = 110011001100110011001100110011...,
wobei, wie zuvor, s der Signifikant und e der Exponent ist. ⓘ
Auf 24 Bit gerundet ergibt sich daraus
- e = -4; s = 110011001100110011001101,
was de facto 0,100000001490116119384765625 in Dezimalzahlen entspricht. ⓘ
Ein weiteres Beispiel ist die reelle Zahl π, die binär als unendliche Folge von Bits dargestellt wird
- 11.0010010000111111011010101000100010000101101000110000100011010011...
ist aber
- 11.0010010000111111011011
wenn sie durch Runden auf eine Genauigkeit von 24 Bit angenähert wird. ⓘ
In binärer Gleitkommadarstellung mit einfacher Genauigkeit wird sie als s = 1,10010010000111111011011 mit e = 1 dargestellt. Dies hat einen dezimalen Wert von
- 3.1415927410125732421875,
Eine genauere Annäherung an den wahren Wert von π ist hingegen
- 3.14159265358979323846264338327950...
Das Ergebnis der Rundung weicht vom wahren Wert um etwa 0,03 Teile pro Million ab und stimmt mit der Dezimaldarstellung von π in den ersten 7 Ziffern überein. Die Differenz ist der Diskretisierungsfehler und wird durch das Epsilon der Maschine begrenzt. ⓘ
Die arithmetische Differenz zwischen zwei aufeinanderfolgenden darstellbaren Fließkommazahlen, die denselben Exponenten haben, wird als Einheit an letzter Stelle (ULP) bezeichnet. Liegt beispielsweise keine darstellbare Zahl zwischen den darstellbaren Zahlen 1,45a70c22hex und 1,45a70c24hex, so ist die ULP 2×16-8 oder 2-31. Für Zahlen mit einem Basis-2-Exponententeil von 0, d. h. Zahlen mit einem absoluten Wert größer oder gleich 1, aber kleiner als 2, ist ein ULP genau 2-23 oder etwa 10-7 in einfacher Genauigkeit und genau 2-53 oder etwa 10-16 in doppelter Genauigkeit. Das vorgeschriebene Verhalten IEEE-konformer Hardware ist, dass das Ergebnis innerhalb der Hälfte eines ULP liegt. ⓘ
Rundungsmodi
Die Rundung wird verwendet, wenn das exakte Ergebnis einer Fließkomma-Operation (oder einer Konvertierung in das Fließkomma-Format) mehr Ziffern erfordern würde, als der Signifikant Ziffern enthält. IEEE 754 verlangt eine korrekte Rundung, d. h. das gerundete Ergebnis ist so, als ob der Wert mit unendlich genauer Arithmetik berechnet und dann gerundet worden wäre (obwohl in der Implementierung nur drei zusätzliche Bits benötigt werden, um dies sicherzustellen). Es gibt mehrere verschiedene Rundungsschemata (oder Rundungsmodi). In der Vergangenheit war die Abrundung der typische Ansatz. Seit der Einführung von IEEE 754 wird die Standardmethode (round to nearest, ties to even, manchmal auch Banker's Rounding genannt) häufiger verwendet. Diese Methode rundet das ideale (unendlich genaue) Ergebnis einer arithmetischen Operation auf den nächstliegenden darstellbaren Wert und gibt diese Darstellung als Ergebnis aus. Bei Gleichstand wird der Wert gewählt, bei dem der Signifikant auf eine gerade Ziffer endet. Die Norm IEEE 754 schreibt vor, dass bei allen grundlegenden algebraischen Operationen, einschließlich Quadratwurzel und Umrechnungen, dieselbe Rundung vorgenommen wird, wenn ein numerisches (nicht-NaN) Ergebnis vorliegt. Das bedeutet, dass die Ergebnisse von IEEE 754-Operationen in allen Bits des Ergebnisses vollständig bestimmt sind, mit Ausnahme der Darstellung von NaNs. ("Bibliotheks"-Funktionen wie Kosinus und log sind nicht vorgeschrieben.) ⓘ
Alternative Rundungsoptionen sind ebenfalls verfügbar. IEEE 754 spezifiziert die folgenden Rundungsmodi:
- round to nearest, wobei Gleichheiten auf die nächste gerade Ziffer an der gewünschten Stelle gerundet werden (die Standardeinstellung und der bei weitem häufigste Modus)
- Runden auf die nächstgelegene Stelle, wobei Bindungen von Null weg gerundet werden (optional für binäre Fließkommazahlen und üblicherweise für Dezimalzahlen verwendet)
- Aufrunden (in Richtung +∞; negative Ergebnisse werden somit gegen Null gerundet)
- Abrunden (in Richtung -∞; negative Ergebnisse werden somit von Null abgerundet)
- Abrunden gegen Null (Abschneiden; dies ähnelt dem üblichen Verhalten bei der Umwandlung von Fließkommazahlen in Ganzzahlen, bei der -3,9 in -3 und 3,9 in 3 umgewandelt wird) ⓘ
Alternative Modi sind nützlich, wenn der eingeführte Fehler begrenzt werden muss. Anwendungen, die einen begrenzten Fehler erfordern, sind Mehrpräzisions-Gleitkommazahlen und Intervallarithmetik. Die alternativen Rundungsmodi sind auch nützlich, um numerische Instabilität zu diagnostizieren: Wenn die Ergebnisse eines Unterprogramms zwischen dem Runden auf + und - unendlich erheblich variieren, ist es wahrscheinlich numerisch instabil und von Rundungsfehlern betroffen. ⓘ
Binär-Dezimal-Konvertierung mit minimaler Anzahl von Ziffern
Die Umwandlung einer binären Gleitkommazahl mit doppelter Genauigkeit in eine Dezimalzeichenfolge ist eine gängige Operation, aber ein Algorithmus, der sowohl genaue als auch minimale Ergebnisse liefert, wurde erst 1990 mit Dragon4 von Steele und White veröffentlicht. Einige der Verbesserungen seither sind:
- David M. Gay's dtoa.c, eine praktische Open-Source-Implementierung vieler Ideen in Dragon4.
- Grisu3, mit einem 4-fachen Geschwindigkeitszuwachs, da es die Verwendung von Bignums beseitigt. Muss mit einem Fallback verwendet werden, da es in ~0,5% der Fälle versagt.
- Errol3, ein immer erfolgreicher Algorithmus, der Grisu3 ähnelt, aber langsamer ist als dieser. Offenbar ist er nicht so gut wie ein früh abbrechender Grisu mit Fallback.
- Ryū, ein immer erfolgreicher Algorithmus, der schneller und einfacher als Grisu3 ist. ⓘ
Viele moderne Laufzeiten für Sprachen verwenden Grisu3 mit einem Dragon4-Fallback. ⓘ
Dezimal-Binär-Konvertierung
Das Problem des Parsens einer dezimalen Zeichenkette in eine binäre FP-Darstellung ist komplex, und ein genauer Parser wurde erst 1990 von Clinger entwickelt (implementiert in dtoa.c). Weitere Arbeiten haben ebenfalls Fortschritte in Richtung eines schnelleren Parsens gemacht. ⓘ
Fließkomma-Operationen
Zur Vereinfachung der Darstellung und des Verständnisses wird in den Beispielen die dezimale Radix mit 7-stelliger Genauigkeit verwendet, wie im Format IEEE 754 decimal32. Die grundlegenden Prinzipien sind bei allen Radixen oder Genauigkeiten gleich, mit der Ausnahme, dass die Normalisierung optional ist (sie hat keinen Einfluss auf den numerischen Wert des Ergebnisses). Hier steht s für den Signifikanten und e für den Exponenten. ⓘ
Addition und Subtraktion
Eine einfache Methode zur Addition von Fließkommazahlen besteht darin, sie zunächst mit demselben Exponenten darzustellen. Im folgenden Beispiel wird die zweite Zahl um drei Ziffern nach rechts verschoben, und man geht dann mit der üblichen Additionsmethode vor:
123456.7 = 1.234567 × 10^5
101.7654 = 1.017654 × 10^2 = 0.001017654 × 10^5 ⓘ
Daraus folgt:
123456.7 + 101.7654 = (1.234567 × 10^5) + (1.017654 × 10^2)
= (1.234567 × 10^5) + (0.001017654 × 10^5)
= (1.234567 + 0.001017654) × 10^5
= 1.235584654 × 10^5 ⓘ
Im Einzelnen:
e=5; s=1.234567 (123456.7)
+ e=2; s=1,017654 (101,7654) ⓘ
e=5; s=1,234567
+ e=5; s=0,001017654 (nach Verschiebung)
--------------------
e=5; s=1,235584654 (wahre Summe: 123558,4654) ⓘ
Dies ist das wahre Ergebnis, die genaue Summe der Operanden. Es wird auf sieben Stellen gerundet und dann gegebenenfalls normalisiert. Das Endergebnis lautet
e=5; s=1,235585 (Endsumme: 123558,5) ⓘ
Die untersten drei Ziffern des zweiten Operanden (654) sind im Wesentlichen verloren. Dies ist ein Rundungsfehler. Im Extremfall kann die Summe von zwei Zahlen, die nicht Null sind, gleich einer der beiden sein:
e=5; s=1,234567
+ e=-3; s=9,876543 ⓘ
e=5; s=1,234567
+ e=5; s=0,00000009876543 (nach Verschiebung)
----------------------
e=5; s=1,23456709876543 (echte Summe)
e=5; s=1,234567 (nach Rundung und Normalisierung) ⓘ
In den obigen konzeptionellen Beispielen sieht es so aus, als müsste der Addierer eine große Anzahl zusätzlicher Ziffern bereitstellen, um eine korrekte Rundung zu gewährleisten; bei sorgfältiger Implementierungstechnik müssen für die binäre Addition oder Subtraktion jedoch nur ein Schutzbit, ein Rundungsbit und ein zusätzliches Sticky-Bit über die Genauigkeit der Operanden hinaus übertragen werden. ⓘ
Ein weiteres Problem des Signifikanzverlusts tritt auf, wenn Annäherungen an zwei nahezu gleiche Zahlen subtrahiert werden. Im folgenden Beispiel sind e = 5; s = 1,234571 und e = 5; s = 1,234567 Annäherungen an die Rationalzahlen 123457,1467 und 123456,659. ⓘ
e=5; s=1.234571
- e=5; s=1.234567
----------------
e=5; s=0,000004
e=-1; s=4.000000 (nach Rundung und Normalisierung) ⓘ
Die Fließkommadifferenz wird genau berechnet, da die Zahlen nahe beieinander liegen - das Sterbenz-Lemma garantiert dies, selbst im Falle eines Unterlaufs, wenn ein allmählicher Unterlauf unterstützt wird. Trotzdem beträgt die Differenz der Originalzahlen e = -1; s = 4,877000, was mehr als 20 % von der Differenz e = -1; s = 4,000000 der Näherungswerte abweicht. Im Extremfall können alle signifikanten Ziffern der Genauigkeit verloren gehen. Diese Annullierung verdeutlicht die Gefahr, die besteht, wenn man davon ausgeht, dass alle Ziffern eines Berechnungsergebnisses von Bedeutung sind. Der Umgang mit den Folgen dieser Fehler ist ein Thema in der numerischen Analyse; siehe auch Genauigkeitsprobleme. ⓘ
Multiplikation und Division
Bei der Multiplikation werden die Signifikanten multipliziert und die Exponenten addiert, das Ergebnis wird gerundet und normalisiert. ⓘ
e=3; s=4.734612
× e=5; s=5,417242
-----------------------
e=8; s=25,648538980104 (echtes Produkt)
e=8; s=25,64854 (nach Rundung)
e=9; s=2,564854 (nach der Normierung) ⓘ
In ähnlicher Weise wird die Division durchgeführt, indem der Exponent des Divisors vom Exponenten des Dividenden subtrahiert und das Signifikat des Dividenden durch das Signifikat des Divisors dividiert wird. ⓘ
Bei der Multiplikation oder Division gibt es keine Aufhebungs- oder Absorptionsprobleme, allerdings können sich kleine Fehler ansammeln, wenn die Operationen nacheinander ausgeführt werden. In der Praxis kann die Art und Weise, wie diese Operationen in der digitalen Logik ausgeführt werden, recht komplex sein (siehe Booth's Multiplikationsalgorithmus und Divisionsalgorithmus). Eine schnelle, einfache Methode ist die Horner-Methode. ⓘ
Literal-Syntax
Literale für Gleitkommazahlen sind sprachabhängig. Typischerweise verwenden sie e oder E um die wissenschaftliche Notation zu bezeichnen. Die Programmiersprache C und der IEEE 754-Standard definieren auch eine hexadezimale Literal-Syntax mit einem Exponenten zur Basis 2 anstelle von 10. Wenn in Sprachen wie C der dezimale Exponent weggelassen wird, ist ein Dezimalpunkt erforderlich, um sie von ganzen Zahlen zu unterscheiden. Andere Sprachen haben keinen Integer-Typ (z. B. JavaScript) oder erlauben die Überladung von numerischen Typen (z. B. Haskell). In diesen Fällen können Ziffernfolgen wie 123
auch Fließkomma-Literale sein. ⓘ
Beispiele für Fließkomma-Literale sind:
99.9
-5000.12
6.02e23
-3e-45
0x1.fffffep+127
in C und IEEE 754 ⓘ
Umgang mit Ausnahmefällen
Bei Fließkommaberechnungen in einem Computer können drei Arten von Problemen auftreten:
- Eine Operation kann mathematisch undefiniert sein, wie z. B. ∞/∞ oder Division durch Null.
- Eine Operation kann prinzipiell zulässig sein, aber vom spezifischen Format nicht unterstützt werden, z. B. die Berechnung der Quadratwurzel aus -1 oder des inversen Sinus von 2 (beides führt zu komplexen Zahlen).
- Eine Operation kann prinzipiell zulässig sein, aber das Ergebnis kann unmöglich im angegebenen Format dargestellt werden, weil der Exponent zu groß oder zu klein ist, um im Exponentenfeld kodiert zu werden. Ein solches Ereignis wird als Überlauf (Exponent zu groß), Unterlauf (Exponent zu klein) oder Denormalisierung (Präzisionsverlust) bezeichnet. ⓘ
Vor dem IEEE-Standard führten solche Bedingungen in der Regel zum Abbruch des Programms oder lösten eine Art Falle aus, die der Programmierer abfangen konnte. Wie dies funktionierte, war systemabhängig, was bedeutete, dass Fließkommaprogramme nicht portabel waren. (Der Begriff "Exception", wie er in IEEE 754 verwendet wird, ist ein allgemeiner Begriff für eine außergewöhnliche Bedingung, die nicht notwendigerweise ein Fehler ist, und unterscheidet sich von dem, der typischerweise in Programmiersprachen wie C++ oder Java definiert wird, in denen eine "Exception" ein alternativer Kontrollfluss ist, der näher an dem liegt, was in der IEEE 754-Terminologie als "Trap" bezeichnet wird.) ⓘ
Hier wird die nach IEEE 754 vorgeschriebene Standardmethode für die Behandlung von Ausnahmen erörtert (das optionale Trapping nach IEEE 754 und andere Modi der "alternativen Ausnahmebehandlung" werden nicht erörtert). Arithmetische Ausnahmen müssen (standardmäßig) in "klebrigen" Status-Flag-Bits aufgezeichnet werden. Sticky" bedeutet, dass sie nicht durch die nächste (arithmetische) Operation zurückgesetzt werden, sondern gesetzt bleiben, bis sie explizit zurückgesetzt werden. Die Verwendung von "sticky"-Flags ermöglicht es somit, die Prüfung außergewöhnlicher Bedingungen bis nach einem vollständigen Fließkomma-Ausdruck oder Unterprogramm zu verzögern: Ohne sie würden außergewöhnliche Bedingungen, die sonst nicht ignoriert werden könnten, eine explizite Prüfung unmittelbar nach jeder Fließkomma-Operation erfordern. Standardmäßig gibt eine Operation immer ein Ergebnis entsprechend der Spezifikation zurück, ohne die Berechnung zu unterbrechen. So liefert 1/0 beispielsweise +∞ und setzt gleichzeitig das Flaggenbit für die Teilung durch Null (diese Voreinstellung von ∞ ist so ausgelegt, dass sie bei nachfolgenden Operationen oft ein endliches Ergebnis liefert und daher sicher ignoriert werden kann). ⓘ
Die ursprüngliche IEEE 754-Norm enthielt jedoch keine Empfehlungen für den Umgang mit solchen Sets von arithmetischen Ausnahme-Flagbits. Während diese also in Hardware implementiert wurden, boten die Implementierungen der Programmiersprachen anfangs in der Regel keine Möglichkeit, auf sie zuzugreifen (abgesehen von Assembler). Im Laufe der Zeit wurden einige Programmiersprachenstandards (z. B. C99/C11 und Fortran) aktualisiert, um Methoden für den Zugriff auf und die Änderung von Status-Flag-Bits zu spezifizieren. Die Version 2008 des IEEE 754-Standards spezifiziert nun einige Operationen für den Zugriff auf und die Handhabung der arithmetischen Flag-Bits. Das Programmiermodell basiert auf einem einzigen Ausführungs-Thread, und die Verwendung dieser Bits durch mehrere Threads muss mit Mitteln außerhalb des Standards gehandhabt werden (z. B. legt C11 fest, dass die Flags thread-lokal gespeichert werden). ⓘ
IEEE 754 spezifiziert fünf arithmetische Ausnahmen, die in den Status-Flags ("sticky bits") aufgezeichnet werden sollen:
- inexact, wird gesetzt, wenn der gerundete (und zurückgegebene) Wert vom mathematisch exakten Ergebnis der Operation abweicht.
- underflow, gesetzt, wenn der gerundete Wert winzig ist (wie in IEEE 754 spezifiziert) und ungenau (oder vielleicht darauf beschränkt, wenn er einen Denormalisierungsverlust aufweist, wie in der Version von 1984 von IEEE 754) und einen subnormalen Wert einschließlich der Nullen zurückgibt.
- overflow, wird gesetzt, wenn der absolute Wert des gerundeten Wertes zu groß ist, um dargestellt werden zu können. Es wird ein unendlicher oder maximal endlicher Wert zurückgegeben, je nachdem, welche Rundung verwendet wird.
- divide-by-zero, wird gesetzt, wenn das Ergebnis bei endlichen Operanden unendlich ist und eine Unendlichkeit, entweder +∞ oder -∞, zurückgegeben wird.
- ungültig, wird gesetzt, wenn ein reellwertiges Ergebnis nicht zurückgegeben werden kann, z. B. sqrt(-1) oder 0/0, und gibt ein stilles NaN zurück.
Der Standardrückgabewert für jede der Ausnahmen ist so konzipiert, dass er in den meisten Fällen das richtige Ergebnis liefert, so dass die Ausnahmen in den meisten Codes ignoriert werden können. inexact liefert ein korrekt gerundetes Ergebnis, und underflow liefert einen denormalisierten kleinen Wert und kann daher fast immer ignoriert werden. divide-by-zero liefert exakt unendlich, was dann typischerweise eine endliche Zahl dividiert und somit Null ergibt, oder andernfalls eine ungültige Ausnahme auslöst, und kann daher ebenfalls typischerweise ignoriert werden. Der effektive Widerstand von n parallel geschalteten Widerständen (siehe Abb. 1) ist zum Beispiel gegeben durch . Wenn ein Kurzschluss entsteht und auf 0 gesetzt, +unendlich zurück, was erwartungsgemäß einen Endwert von 0 ergibt (ein weiteres Beispiel findet sich in der Begründung des IEEE-754-Entwurfs für einen fortgesetzten Bruch).
Überlauf- und Ungültigkeitsausnahmen können in der Regel nicht ignoriert werden, stellen aber nicht notwendigerweise Fehler dar: Beispielsweise kann eine Routine zur Wurzelsuche im Rahmen ihres normalen Betriebs eine übergebene Funktion bei Werten außerhalb ihrer Domäne auswerten und NaN und ein Flag für eine ungültige Ausnahme zurückgeben, das ignoriert werden muss, bis ein nützlicher Startpunkt gefunden wird. ⓘ
Genauigkeits-Probleme
Die Tatsache, dass Fließkommazahlen nicht alle reellen Zahlen genau darstellen können und dass Fließkommaoperationen keine echten arithmetischen Operationen genau darstellen können, führt zu vielen überraschenden Situationen. Dies hängt mit der endlichen Genauigkeit zusammen, mit der Computer im Allgemeinen Zahlen darstellen. ⓘ
Beispielsweise bedeutet die Nichtdarstellbarkeit von 0,1 und 0,01 (im Binärformat), dass das Ergebnis des Versuchs, 0,1 zu quadrieren, weder 0,01 noch die darstellbare Zahl ist, die diesem Wert am nächsten kommt. In der 24-Bit-Darstellung (einfache Genauigkeit) wurde 0,1 (dezimal) früher als e = −4; s = 110011001100110011001101 angegeben, das ist
Die Quadrierung dieser Zahl ergibt
Die Quadrierung mit einfach präziser Fließkommahardware (mit Rundung) ergibt
Die darstellbare Zahl, die 0,01 am nächsten kommt, ist jedoch
Die Nicht-Darstellbarkeit von π (und π/2) bedeutet auch, dass eine versuchte Berechnung von tan(π/2) kein unendliches Ergebnis liefert und auch in den üblichen Fließkommaformaten nicht zum Überlauf führt (eine genaue Implementierung von tan vorausgesetzt). Es ist für Standard-Gleitkomma-Hardware einfach nicht möglich, die Berechnung von tan(π/2) zu versuchen, da π/2 nicht exakt dargestellt werden kann. Diese Berechnung in C:
/* Genügend Ziffern, um sicher zu sein, dass wir die richtige Annäherung erhalten. */
double pi = 3,1415926535897932384626433832795;
double z = tan(pi/2.0);
wird ein Ergebnis von 16331239353195370.0 liefern. In einfacher Genauigkeit (unter Verwendung der Funktion tanf
) ist das Ergebnis -22877332.0. ⓘ
Aus demselben Grund wird eine versuchte Berechnung von sin(π) nicht Null ergeben. Das Ergebnis wird (ungefähr) 0,1225×10-15 in doppelter Genauigkeit oder -0,8742×10-7 in einfacher Genauigkeit sein. ⓘ
Während die Addition und Multiplikation mit Gleitkommazahlen beide kommutativ sind (a + b = b + a und a × b = b × a), aber sie sind nicht unbedingt assoziativ. Das heißt, (a + b) + c ist nicht notwendigerweise gleich a + (b + c). 7-stellige Dezimalarithmetik mit Signifikanten:
a = 1234,567, b = 45,67834, c = 0,0004 ⓘ
(a + b) + c:
1234.567 (a)
+ 45.67834 (b)
____________
1280,24534 rundet auf 1280,245 ⓘ
1280,245 (a + b)
+ 0.0004 (c)
____________
1280,2454 rundet auf 1280,245 ← (a + b) + c ⓘ
a + (b + c):
45.67834 (b)
+ 0.0004 (c)
____________
45.67874 ⓘ
1234.567 (a)
+ 45,67874 (b + c)
____________
1280,24574 rundet auf 1280,246 ← a + (b + c) ⓘ
Sie sind auch nicht unbedingt distributiv. Das heißt, (a + b) × c ist nicht unbedingt dasselbe wie a × c + b × c:
1234.567 × 3.333333 = 4115.223
1.234567 × 3.333333 = 4.115223
4115.223 + 4.115223 = 4119.338
aber
1234.567 + 1.234567 = 1235.802
1235.802 × 3.333333 = 4119.340 ⓘ
Neben dem Verlust der Signifikanz, der Unfähigkeit, Zahlen wie π und 0,1 exakt darzustellen, und anderen leichten Ungenauigkeiten können folgende Phänomene auftreten:
- Annullierung: Die Subtraktion von nahezu gleichen Operanden kann zu einem extremen Genauigkeitsverlust führen. Wenn wir zwei fast gleiche Zahlen subtrahieren, setzen wir die höchstwertigen Ziffern auf Null, so dass nur noch die unbedeutenden und damit fehlerhaften Ziffern übrig bleiben. Bei der Bestimmung der Ableitung einer Funktion wird zum Beispiel folgende Formel verwendet:
Intuitiv würde man sich eine h sehr nahe bei Null liegen; bei der Verwendung von Fließkommaoperationen ergibt die kleinste Zahl jedoch nicht die beste Annäherung an eine Ableitung. Wenn h kleiner wird, steigt die Differenz zwischen f(a + h) und f(a) kleiner, so dass die signifikantesten und die am wenigsten fehlerhaften Ziffern wegfallen und die fehlerhaftesten Ziffern an Bedeutung gewinnen. Infolgedessen führt die kleinstmögliche Zahl von h zu einer fehlerhafteren Annäherung an eine Ableitung führen als eine etwas größere Zahl. Dies ist vielleicht das häufigste und schwerwiegendste Genauigkeitsproblem.
- Umrechnungen in Ganzzahlen sind nicht intuitiv: Die Umrechnung von (63,0/9,0) in Ganzzahlen ergibt 7, aber die Umrechnung von (0,63/0,09) kann 6 ergeben. Das liegt daran, dass Umrechnungen im Allgemeinen abschneiden und nicht runden. Floor- und Ceiling-Funktionen können zu Ergebnissen führen, die um eins vom intuitiv erwarteten Wert abweichen.
- Begrenzter Exponentenbereich: Die Ergebnisse können überlaufen und unendlich ergeben, oder sie können unterlaufen und eine subnormale Zahl oder Null ergeben. In diesen Fällen geht die Genauigkeit verloren.
- Die Prüfung auf sichere Division ist problematisch: Die Prüfung, dass der Divisor nicht Null ist, garantiert nicht, dass eine Division nicht überläuft.
- Die Prüfung auf Gleichheit ist problematisch. Zwei Berechnungssequenzen, die mathematisch gleich sind, können durchaus unterschiedliche Fließkommawerte ergeben. ⓘ
Zwischenfälle
- Am 25. Februar 1991 verhinderte ein Bedeutungsverlust in einer MIM-104 Patriot-Raketenbatterie, dass diese eine ankommende Scud-Rakete in Dhahran, Saudi-Arabien, abfangen konnte, was zum Tod von 28 Soldaten des 14th Quartermaster Detachment der US-Armee beitrug. ⓘ
Maschinengenauigkeit und Rückwärtsfehleranalyse
Die Maschinengenauigkeit ist eine Größe, die die Genauigkeit eines Gleitkommasystems charakterisiert und bei der Rückwärtsfehleranalyse von Gleitkomma-Algorithmen verwendet wird. Sie wird auch als Rundungseinheit oder Maschinen-Epsilon bezeichnet. Normalerweise wird er mit Εmach bezeichnet, hängt sein Wert von der verwendeten Rundung ab. ⓘ
Beim Runden auf Null,
Dies ist wichtig, da es den relativen Fehler bei der Darstellung einer reellen Zahl ungleich Null einschränkt x innerhalb des normierten Bereichs eines Gleitkommasystems:
Die Rückwärtsfehleranalyse, deren Theorie von James H. Wilkinson entwickelt und popularisiert wurde, kann verwendet werden, um nachzuweisen, dass ein Algorithmus, der eine numerische Funktion implementiert, numerisch stabil ist. Der grundlegende Ansatz besteht darin, zu zeigen, dass das berechnete Ergebnis aufgrund von Rundungsfehlern zwar nicht exakt korrekt ist, aber die exakte Lösung für ein naheliegendes Problem mit leicht gestörten Eingabedaten darstellt. Wenn die erforderliche Störung klein ist, etwa in der Größenordnung der Unsicherheit in den Eingabedaten, dann sind die Ergebnisse in gewissem Sinne so genau, wie es die Daten "verdienen". Der Algorithmus wird dann als rückwärtsstabil definiert. Stabilität ist ein Maß für die Empfindlichkeit eines bestimmten numerischen Verfahrens gegenüber Rundungsfehlern; im Gegensatz dazu zeigt die Zustandszahl einer Funktion für ein bestimmtes Problem die inhärente Empfindlichkeit der Funktion gegenüber kleinen Störungen in ihrer Eingabe an und ist unabhängig von der zur Lösung des Problems verwendeten Implementierung. ⓘ
Als triviales Beispiel betrachten wir einen einfachen Ausdruck, der das innere Produkt von Vektoren (der Länge zwei) und , dann
wobei ⓘ
wobei ⓘ
per Definition die Summe von zwei geringfügig gestörten (in der Größenordnung von Εmach) Eingabedaten ist und somit rückwärts stabil ist. Für realistischere Beispiele in der numerischen linearen Algebra siehe Higham 2002 und andere Referenzen unten. ⓘ
Minimierung der Auswirkungen von Genauigkeitsproblemen
Obwohl, wie bereits erwähnt, einzelne arithmetische Operationen nach IEEE 754 mit einer Genauigkeit von einem halben ULP garantiert sind, können kompliziertere Formeln aufgrund von Rundungsfehlern größere Fehler aufweisen. Der Genauigkeitsverlust kann beträchtlich sein, wenn ein Problem oder seine Daten schlecht konditioniert sind, was bedeutet, dass das korrekte Ergebnis überempfindlich auf winzige Störungen in seinen Daten reagiert. Aber auch bei Funktionen, die gut konditioniert sind, kann es zu großen Genauigkeitsverlusten kommen, wenn ein Algorithmus verwendet wird, der für diese Daten numerisch instabil ist: scheinbar gleichwertige Formulierungen von Ausdrücken in einer Programmiersprache können sich in ihrer numerischen Stabilität deutlich unterscheiden. Ein Ansatz zur Beseitigung des Risikos eines solchen Genauigkeitsverlusts ist der Entwurf und die Analyse numerisch stabiler Algorithmen, was ein Ziel des als numerische Analyse bekannten Zweigs der Mathematik ist. Ein weiterer Ansatz, der vor dem Risiko numerischer Instabilitäten schützen kann, ist die Berechnung von Zwischenwerten (Scratch-Werten) in einem Algorithmus mit einer höheren Genauigkeit als für das Endergebnis erforderlich, wodurch dieses Risiko beseitigt oder um Größenordnungen verringert werden kann: IEEE 754 Quadruple Precision und Extended Precision sind für diesen Zweck konzipiert, wenn mit doppelter Genauigkeit gerechnet wird. ⓘ
Der folgende Algorithmus ist zum Beispiel eine direkte Implementierung zur Berechnung der Funktion A(x) = (x-1) / (exp(x-1) - 1), die bei 1,0 gut konditioniert ist. Es kann jedoch gezeigt werden, dass sie numerisch instabil ist und bis zur Hälfte der von der Arithmetik getragenen signifikanten Ziffern verliert, wenn sie nahe 1,0 berechnet wird.
double A(double X)
{
double Y, Z; // [1]
Y = X - 1,0;
Z = exp(Y);
if (Z != 1,0)
Z = Y / (Z - 1.0); // [2]
Z zurückgeben;
} <span title="Aus: Englische Wikipedia, Abschnitt "Minimizing the effect of accuracy problems"" class="plainlinks">[https://en.wikipedia.org/wiki/Floating-point_arithmetic#Minimizing_the_effect_of_accuracy_problems <span style="color:#dddddd">ⓘ</span>]</span>
Wenn jedoch alle Zwischenberechnungen in erweiterter Genauigkeit durchgeführt werden (z.B. durch Setzen von Zeile [1] auf C99 long double
), dann kann die volle Genauigkeit des Endergebnisses der Verdopplung beibehalten werden. Alternativ dazu zeigt eine numerische Analyse des Algorithmus, dass die folgende, nicht offensichtliche Änderung in Zeile [2] vorgenommen werden kann:
Z = log(Z) / (Z - 1,0);
dann wird der Algorithmus numerisch stabil und kann bis zur vollen doppelten Genauigkeit rechnen. ⓘ
Um die Eigenschaften solcher sorgfältig konstruierten, numerisch stabilen Programme zu erhalten, ist eine sorgfältige Behandlung durch den Compiler erforderlich. Bestimmte "Optimierungen", die Compiler vornehmen können (z. B. das Umordnen von Operationen), können den Zielen einer gut funktionierenden Software entgegenwirken. Es gibt einige Kontroversen über die Schwächen von Compilern und Sprachdesigns in diesem Bereich: C99 ist ein Beispiel für eine Sprache, in der solche Optimierungen sorgfältig spezifiziert sind, um die numerische Präzision zu erhalten. Siehe die externen Referenzen am Ende dieses Artikels. ⓘ
Eine detaillierte Behandlung der Techniken für das Schreiben von qualitativ hochwertiger Fließkomma-Software würde den Rahmen dieses Artikels sprengen, und der Leser wird auf die anderen Referenzen am Ende dieses Artikels verwiesen. Kahan schlägt mehrere Faustregeln vor, die das Risiko numerischer Anomalien um Größenordnungen verringern können, und zwar zusätzlich zu oder anstelle einer sorgfältigeren numerischen Analyse. Dazu gehören: wie oben erwähnt, die Berechnung aller Ausdrücke und Zwischenergebnisse in der höchsten von der Hardware unterstützten Genauigkeit (eine gängige Faustregel ist die doppelte Genauigkeit des gewünschten Ergebnisses, d. h. (eine gängige Faustregel ist, die doppelte Genauigkeit des gewünschten Ergebnisses zu verwenden, d. h. mit doppelter Genauigkeit für ein einfaches Endergebnis oder mit doppelter erweiterter oder vierfacher Genauigkeit für Ergebnisse mit doppelter Genauigkeit zu rechnen); und das Runden von Eingabedaten und Ergebnissen auf nur die erforderliche und von den Eingabedaten unterstützte Genauigkeit (eine über die erforderliche und von den Eingabedaten unterstützte Genauigkeit hinausgehende Genauigkeit im Endergebnis kann irreführend sein, erhöht die Speicherkosten und verringert die Geschwindigkeit, und die überschüssigen Bits können die Konvergenz numerischer Verfahren beeinträchtigen: insbesondere die erste Form des unten aufgeführten iterativen Beispiels konvergiert korrekt, wenn diese Faustregel verwendet wird). Es folgen kurze Beschreibungen einiger weiterer Probleme und Techniken. ⓘ
Da Dezimalbrüche in der binären Fließkommadarstellung oft nicht exakt dargestellt werden können, ist diese Art der Arithmetik am besten geeignet, wenn sie einfach zur Messung realer Größen über einen weiten Bereich von Maßstäben verwendet wird (z. B. die Umlaufzeit eines Mondes um den Saturn oder die Masse eines Protons), und am schlechtesten, wenn von ihr erwartet wird, dass sie die Wechselwirkungen von Größen modelliert, die als exakte Dezimalketten ausgedrückt werden. Ein Beispiel für den letzten Fall sind Finanzberechnungen. Aus diesem Grund verwendet Finanzsoftware in der Regel keine binäre Fließkommadarstellung. Der Datentyp "decimal" der Programmiersprachen C# und Python und die Dezimalformate des Standards IEEE 754-2008 wurden entwickelt, um die Probleme der binären Fließkommadarstellung zu vermeiden, wenn sie auf von Menschen eingegebene exakte Dezimalwerte angewandt werden, und um dafür zu sorgen, dass sich die Arithmetik immer wie erwartet verhält, wenn Zahlen in dezimaler Form ausgedruckt werden. ⓘ
Die Erwartungen der Mathematik werden im Bereich der Gleitkommaberechnungen möglicherweise nicht erfüllt. Es ist beispielsweise bekannt, dass , und dass Diese Tatsachen sind jedoch nicht verlässlich, wenn die betreffenden Größen das Ergebnis von Gleitkommaberechnungen sind. ⓘ
Die Verwendung des Gleichheitstests (if (x==y) ...
) erfordert beim Umgang mit Fließkommazahlen Vorsicht. Selbst einfache Ausdrücke wie 0,6/0,2-3==0 werden auf den meisten Computern nicht zutreffen (in IEEE 754 Double Precision ist 0,6/0,2 - 3 zum Beispiel ungefähr gleich -4,44089209850063e-16). Daher werden solche Tests manchmal durch "unscharfe" Vergleiche ersetzt (if (abs(x-y) < epsilon) ...
, wobei epsilon hinreichend klein und auf die Anwendung zugeschnitten ist, z. B. 1,0E-13). Es ist sehr unterschiedlich, ob es sinnvoll ist, dies zu tun, und kann eine numerische Analyse zur Begrenzung von epsilon erfordern. Die aus der primären Datendarstellung abgeleiteten Werte und ihre Vergleiche sollten in einer größeren, erweiterten Genauigkeit durchgeführt werden, um das Risiko solcher Inkonsistenzen aufgrund von Rundungsfehlern zu minimieren. Oft ist es besser, den Code so zu organisieren, dass solche Tests überflüssig sind. In der rechnergestützten Geometrie kann beispielsweise mit Hilfe von Methoden der adaptiven Präzision oder der exakten Arithmetik genau geprüft werden, ob ein Punkt außerhalb oder auf einer durch andere Punkte definierten Linie oder Ebene liegt. ⓘ
Kleine Fehler in der Gleitkommaarithmetik können sich vergrößern, wenn mathematische Algorithmen Operationen sehr oft durchführen. Einige Beispiele sind die Inversion von Matrizen, die Berechnung von Eigenvektoren und das Lösen von Differentialgleichungen. Diese Algorithmen müssen sehr sorgfältig entworfen werden, wobei numerische Ansätze wie die iterative Verfeinerung verwendet werden müssen, wenn sie gut funktionieren sollen. ⓘ
Die Summierung eines Vektors von Fließkommazahlen ist ein grundlegender Algorithmus im wissenschaftlichen Rechnen, und daher ist es wichtig zu wissen, wann ein Bedeutungsverlust auftreten kann. Wenn man beispielsweise eine sehr große Anzahl von Zahlen addiert, sind die einzelnen Summanden im Vergleich zur Summe sehr klein. Dies kann zu einem Bedeutungsverlust führen. Eine typische Addition würde dann etwa so aussehen
3253.671 + 3.141276 ----------- 3256.812
Die unteren 3 Ziffern der Summanden gehen praktisch verloren. Angenommen, man muss viele Zahlen addieren, die alle ungefähr gleich 3 sind. Nachdem 1000 davon addiert worden sind, beträgt die laufende Summe etwa 3000; die verlorenen Ziffern werden nicht wiedergewonnen. Der Kahan-Summenalgorithmus kann verwendet werden, um die Fehler zu reduzieren. ⓘ
Rundungsfehler können die Konvergenz und Genauigkeit von iterativen numerischen Verfahren beeinträchtigen. Archimedes näherte sich beispielsweise π an, indem er die Umfänge von Polygonen berechnete, die einen Kreis ein- und umschreiben, wobei er mit Sechsecken begann und die Anzahl der Seiten sukzessive verdoppelte. Wie bereits erwähnt, können die Berechnungen auf eine Weise umgestellt werden, die mathematisch gleichwertig, aber weniger fehleranfällig ist (numerische Analyse). Es gibt zwei Formen der Rekursionsformel für das umschriebene Vieleck:
- Erste Form:
- zweite Form:
- , konvergierend als ⓘ
Hier eine Berechnung unter Verwendung der IEEE-"Double"-Arithmetik (ein Signifikant mit 53 Bit Genauigkeit):
i 6 × 2i × ti, erste Form 6 × 2i × ti, zweite Form --------------------------------------------------------- 0 3.4641016151377543863 3.4641016151377543863 1 3.2153903091734710173 3.2153903091734723496 2 3.1596599420974940120 3.1596599420975006733 3 3.1460862151314012979 3.1460862151314352708 4 3.1427145996453136334 3.1427145996453689225 5 3.1418730499801259536 3.1418730499798241950 6 3.1416627470548084133 3.1416627470568494473 7 3.1416101765997805905 3.1416101766046906629 8 3.1415970343230776862 3.1415970343215275928 9 3.1415937488171150615 3.1415937487713536668 10 3.1415929278733740748 3.1415929273850979885 11 3.1415927256228504127 3.1415927220386148377 12 3.1415926717412858693 3.1415926707019992125 13 3.1415926189011456060 3.1415926578678454728 14 3.1415926717412858693 3.1415926546593073709 15 3.1415919358822321783 3.1415926538571730119 16 3.1415926717412858693 3.1415926536566394222 17 3.1415810075796233302 3.1415926536065061913 18 3.1415926717412858693 3.1415926535939728836 19 3.1414061547378810956 3.1415926535908393901 20 3.1405434924008406305 3.1415926535900560168 21 3.1400068646912273617 3.1415926535898608396 22 3.1349453756585929919 3.1415926535898122118 23 3.1400068646912273617 3.1415926535897995552 24 3.2245152435345525443 3.1415926535897968907 25 3.1415926535897962246 26 3.1415926535897962246 27 3.1415926535897962246 28 3.1415926535897962246 Der wahre Wert ist 3,14159265358979323846264338327... ⓘ
Während die beiden Formen der Rekursionsformel mathematisch eindeutig äquivalent sind, subtrahiert die erste Form 1 von einer Zahl, die extrem nahe bei 1 liegt, was zu einem zunehmend problematischen Verlust signifikanter Ziffern führt. Bei wiederholter Anwendung der Rekursion verbessert sich die Genauigkeit zunächst, verschlechtert sich dann aber. Sie wird nie besser als etwa 8 Ziffern, obwohl die 53-Bit-Arithmetik eine Genauigkeit von etwa 16 Ziffern haben sollte. Wenn die zweite Form der Rekursion verwendet wird, konvergiert der Wert auf 15 Stellen Genauigkeit. ⓘ
Optimierung des "schnellen Rechnens"
Die bereits erwähnte fehlende Assoziativität von Fließkomma-Operationen bedeutet, dass Compiler arithmetische Ausdrücke nicht so effektiv neu anordnen können wie bei der Ganzzahl- und Festkomma-Arithmetik, was Optimierungen wie die Eliminierung gemeinsamer Unterausdrücke und die Auto-Vektorisierung behindert. Die Option "fast math" vieler Compiler (ICC, GCC, Clang, MSVC...) schaltet die Reassoziation zusammen mit unsicheren Annahmen wie dem Fehlen von NaN und unendlichen Zahlen in IEEE 754 ein. Einige Compiler bieten auch granularere Optionen, um nur die Reassoziation zu aktivieren. In beiden Fällen ist der Programmierer für den Teil des Programms, der "schnelle" Mathematik verwendet, vielen der oben genannten Präzisionsfallen ausgesetzt. ⓘ
In einigen Compilern (GCC und Clang) kann das Einschalten der "schnellen" Mathematik dazu führen, dass das Programm beim Start subnormale Fließkommazahlen deaktiviert, was sich nicht nur auf das Fließkomma-Verhalten des generierten Codes auswirkt, sondern auch auf jedes Programm, das diesen Code als Bibliothek verwendet. ⓘ
In den meisten Fortran-Compilern, die nach dem Fortran-Standard ISO/IEC 1539-1:2004 zulässig sind, ist die Reassoziation die Standardeinstellung, wobei ein Bruch durch die Einstellung "protect parens" (ebenfalls standardmäßig aktiviert) weitgehend verhindert wird. Diese Einstellung verhindert, dass der Compiler über die Grenzen von Klammern hinaus reassoziiert. Der Intel Fortran Compiler ist ein bemerkenswerter Ausreißer. ⓘ
Ein häufiges Problem in der "schnellen" Mathematik besteht darin, dass Unterausdrücke nicht immer identisch optimiert werden, was zu unerwarteten Unterschieden führt. Eine Interpretation des Problems ist, dass "schnelle" Mathematik, wie sie derzeit implementiert ist, eine schlecht definierte Semantik hat. Ein Versuch, "schnelle" mathematische Optimierungen zu formalisieren, findet sich in Icing, einem verifizierten Compiler. ⓘ
Grundlagen
Problem
Alle (mechanischen oder elektronischen) Rechenhilfsmittel vom Abakus bis zum Computer verwenden als einfachste Form der Zahldarstellung Festkommazahlen. Dabei wird eine meistens begrenzte Ziffernfolge gespeichert und an festgelegter Stelle das Komma angenommen. ⓘ
Bei größeren Rechnungen treten unweigerlich Überläufe auf, die eine Skalierung der Werte und eine erneute Durchrechnung erforderlich machen, um Endergebnis und alle Zwischenergebnisse in den erlaubten Wertebereich zu bringen. Diese Skalierung ist zeitraubend und muss automatisiert werden. ⓘ
Exponentialschreibweise
Ein naheliegender und direkt zu Gleitkommazahlen führender Gedanke ist dabei, bei jedem Wert die genaue Stelle des Kommas zusätzlich zu speichern. Das bedeutet mathematisch nichts anderes als die Darstellung der Zahl mit zwei Werten, der Mantisse und dem Exponenten , so dass . Die Freiheit bei der Wahl des Exponenten kann genutzt werden, um die Mantisse in einen festgelegten Wertebereich, zum Beispiel zu bringen. Dieser Schritt heißt Normalisierung der Mantisse. ⓘ
Beispiel: Der Wert der Lichtgeschwindigkeit beträgt
Nur die Mantisse der letzten Darstellung ist normalisiert. ⓘ
Diese Schreibweise wird von Physikern und Mathematikern schon seit langem verwendet, um sehr große und sehr kleine Zahlen anzugeben. Noch heute wird deshalb die Gleitkommaschreibweise auf Taschenrechnern speziell als wissenschaftliches Format (sci) bezeichnet. ⓘ
In Programmiersprachen wird für die Notation von Gleitkommazahlen im Quelltext und für ihre Ein- und Ausgabe eine kompakte Variante der Exponentialschreibweise verwendet, z. B. 2.99792458e8
(= 2,997.924.58 · 108) oder 3.141592653589793d0
(d
wird bei Zahlen in doppelter Genauigkeit benutzt). Das e
bzw. d
– ursprünglich die Großbuchstaben E
und D
– ist also als Kurzform von „mal 10 hoch“ zu verstehen. In der Sprache Algol 60 war dafür ein eigenes Zeichen ⏨
(Basiszehn) vorgesehen, das zwar auf manchen Ein- und Ausgabegeräten damaliger Rechner vorhanden war, aber erst 2002, also nach der Verwendungszeit von Algol 60, als Unicode-Zeichen U+23E8 in einen genormten Zeichencode aufgenommen wurde. ⓘ
Gleitkommaarithmetik
Bei Rechnungen mit Gleitkommazahlen wird jede Zahl und jedes Zwischenergebnis individuell skaliert (im Gegensatz zu einer globalen Skalierung). Die Skalierung (Berechnung des Exponenten) jedes Zwischenergebnisses erfordert zusätzlichen Rechenaufwand und wurde deshalb bis weit in die 1980er Jahre nach Möglichkeit vermieden. So hatten die damaligen PCs standardmäßig keinen Gleitkommaprozessor. Ein weiterer Faktor war der höhere Speicherbedarf von Gleitkommazahlen, der nur durch Verzicht auf höhere Genauigkeit eingeschränkt werden konnte. Dementsprechend hatten zunächst nur die Höchstleistungsrechner (number cruncher) eine Gleitkommaarithmetik oder wenigstens eine Hardwareunterstützung einer Software-Gleitkommaarithmetik. ⓘ
Die Wahl der Basis 10 ist willkürlich und nur dem üblichen Zehnersystem geschuldet. Gleitkommazahlen können mit beliebigen Basen dargestellt werden, im Allgemeinen gilt mit einer beliebig gewählten Basis . Rechenanlagen verwenden (vorherrschend), (heute selten) oder (z. B. für Finanzmathematik, siehe unten). Bei beliebiger Basis ist die Bedingung für normalisierte Zahlen . ⓘ
Darstellung
Im vorigen Abschnitt wurden die grundlegenden Parameter einer Gleitkommazahl bereits vorgestellt. Es sind Basis , Anzahl der Mantissenstellen und Anzahl der Exponentenstellen . Hinzu kommen weitere Parameter, die beim Rechnen die Rechenoperationen erleichtern sollen. In diesem Abschnitt werden Parameter und Bitfelder einer allgemeinen Gleitkommazahl kurz beschrieben. ⓘ
Basis
Ein Parameter ist die gewählte Basis . Zahlen, die von Menschen direkt verarbeitet werden, verwenden entweder oder . In diesem speziellen Fall verwendet man für den Exponenten die Vorsätze Kilo=10001, Mega=10002, Giga=10003, Tera=10004 und Milli=1000−1, Mikro=1000−2, Nano=1000−3, Piko=1000−4 des internationalen Einheitensystems. ⓘ
Im Computer haben sich das Dualsystem und seine Verwandten durchgesetzt und es sind die Basen , und üblich. Seit der Norm für Gleitkommazahlen IEEE 754 wird in modernen Computern fast ausschließlich die Basis verwendet. ⓘ
Kurzdarstellung der Parameter
In den letzten Jahren hat sich die folgende Kurzdarstellung der wesentlichen Parameter , , und eines Gleitkommasystems durchgesetzt. Dabei schreibt man durch Punkte getrennt die Größen 1, , , und in genau dieser Reihenfolge auf. Die 1 ist dabei die Anzahl der Vorzeichenbits. Eine IEEE-754-Single-Zahl mit 1 Vorzeichenbit, 8 Exponentenbits und 23 Mantissenbits ist also eine 1.8.23.127.2 Gleitkommazahl. Geht die Basis und der Bias aus dem Zusammenhang hervor, kann beides weggelassen werden und man spricht von einer 1.8.23-Gleitkommazahl. ⓘ
Eine zweite gängige Schreibweise lässt das Vorzeichenbit weg und gibt nur Mantissenlänge und Exponentenlänge an: s23e8. ⓘ
Mit diesen Schreibweisen gilt für IEEE-754-Zahlen:
half: 1.5.10.15.2, 1.5.10 oder s10e5
single: 1.8.23.127.2, 1.8.23 oder s23e8
double: 1.11.52.1023.2, 1.11.52 oder s52e11
quad: 1.15.112.16383.2, 1.15.16383 oder s112e15
oct: 1.19.236.262143.2, 1.19.236.262143 oder s236e19 ⓘ
Eigenschaften einer Gleitkommaarithmetik
Gleitkommazahlen warten besonders für den mathematischen Laien mit einigen Überraschungen auf, die auch oft das Ergebnis von Taschenrechner- und Computerrechnungen beeinflussen. Am wichtigsten sind außer Kraft gesetzte geläufige mathematische Rechenregeln. Wer intensiv mit einem Rechenhilfsmittel arbeitet, muss diese Eigenschaften kennen. Sie gehen auf die begrenzte Genauigkeit zurück, mit der Mantisse und Exponent gespeichert werden. Die Konsequenz dieser Begrenzung wird klar, wenn man sich überlegt, dass die unendlich vielen reellen Zahlen durch endlich viele Ziffernkombinationen dargestellt werden sollen. Man kann sich die Gleitkommazahlen im Definitionsbereich eines Systems als lange Tabelle diskreter Werte vorstellen. Eine Gleitkommafunktion ordnet dann jedem Wert dieser Liste einen anderen Wert zu. Analoges gilt für zwei- und mehrstellige Operationen. Im Artikel Minifloats sind die entsprechenden Wertebereiche grafisch dargestellt. ⓘ
Daraus resultiert die leichte bis absolute Ungenauigkeit der Rechnungen und die außer Kraft gesetzte Gültigkeit geläufiger mathematischer Rechenregeln. ⓘ
Auslöschung
Unter Auslöschung versteht man den Effekt, dass bei der Subtraktion fast gleich großer Zahlen das Ergebnis falsch wird. ⓘ
Beispiel: Subtrahiert man und die Zahl 3,141 in einer vierstelligen Gleitkommaarithmetik (, ), so erwartet der Laie als korrekt gerundetes Ergebnis . ⓘ
Tatsächlich erhält man als Ergebnis : Der vierstellige gerundete Wert von ist , damit wird das Ergebnis der Rechnung zu . Zu diesem Ergebnis kommt es, da schon die Ausgangsgrößen, insbesondere in der Gleitkommaarithmetik dargestellt sind und eben nicht exakt vorliegen. ⓘ
Zahlen verschiedener Größenordnung (Absorption)
Die Addition bzw. Subtraktion einer betragsmäßig viel kleineren Zahl ändert die größere Zahl nicht. ⓘ
Im Beispiel der vierstelligen Dezimalarithmetik (, ) ändert die Addition von 0,001 zu 100 am größeren Operanden nichts. Dasselbe gilt für die Subtraktion:
(Die Ziffern hinter dem Strich | entfallen bei der Skalierung) ⓘ
Unterlauf
Da es in der Gleitkommadarstellung eine kleinste positive Zahl gibt, unterhalb derer kein Wert mehr dargestellt werden kann, wird ein Ergebnis in diesem Bereich meistens durch 0 repräsentiert. In diesem Fall spricht man von einem Unterlauf (engl. underflow). Handelt es sich um ein Zwischenergebnis, so ist an diesem Punkt jede Information über das Ergebnis verloren gegangen. In manchen Fällen wird die Genauigkeit des Endergebnisses davon nicht berührt, aber in anderen Fällen kann das resultierende Endergebnis auch komplett falsch sein. ⓘ
Ungültigkeit der Assoziativ- und Distributivgesetze
Die Addition und die Multiplikation von Gleitkommazahlen sind nicht assoziativ, das heißt im Allgemeinen gilt:
Die Addition und Multiplikation von Gleitkommazahlen sind auch nicht distributiv, das heißt im Allgemeinen gilt:
Lösbarkeit von Gleichungen
In einer Gleitkommaarithmetik haben manche normalerweise unlösbare Gleichungen eine Lösung. Dieser Effekt wird sogar ausgenutzt, um ein solches Gleitkommasystem zu beschreiben. ⓘ
Beispiel: Im Bereich der reellen Zahlen hat die Gleichung für keine Lösung. ⓘ
In einer Gleitkommaarithmetik hat diese Gleichung viele Lösungen, nämlich alle Zahlen, die zu klein sind, um bei der Summe noch einen Effekt zu ergeben. Wieder mit dem Beispiel vierstelliger Dezimalbrüche (, ) gilt (Der Strich | markiert die bei der Addition entfallenden Stellen):
- 1 + 1e−3 = 1,000 + 0,001|000000… = 1,000 + 0,001 = 1,001 > 1
- 1 + 1e−4 = 1,000 + 0,000|10000… = 1,000 + 0,000 = 1,000 = 1
- 1 + 2,3e−5 = 1,000 + 0,000|023000… = 1,000 + 0,000 = 1,000 = 1 ⓘ
Die schon oben erwähnte kleinste Zahl , die zu 1 addiert werden kann und ein von 1 verschiedenes Ergebnis liefert (; minimal!) nennt man Maschinengenauigkeit. ⓘ
Konversionen
Wenn die Basis verschieden von 10 ist, müssen die Zahlen zwischen dem vorliegenden Gleitkommasystem und dem Dezimalsystem konvertiert werden, um eine menschenlesbare Darstellung zu erhalten. Das wird meist schnell (und oft ungenau) programmiert. Eine schon alte und wichtige Forderung an diese Konversion ist ihre bitgenaue Umkehrbarkeit. Ein im Dezimalsystem dargestelltes Ergebnis soll wieder eingelesen werden können und bitgenau dieselbe Darstellung im Gleitkommasystem reproduzieren. ⓘ
Diese Forderung wird häufig nicht beachtet. Eine Ausnahme ist hier Java, das den folgenden Satz beachtet: Satz: Man kann zeigen, dass es nicht ausreicht, die aufgrund der Mantissengenauigkeit berechnete Anzahl der Dezimalstellen aufzurunden und diese Dezimalstellen gerundet zu produzieren. Eine einzige weitere Stelle reicht jedoch aus (Theorem 15). Das ist der Grund, warum in der Darstellung reeller Zahlen, die von Java-Programmen produziert werden, immer eine zusätzliche und scheinbar überflüssige Stelle erscheint. ⓘ
Prüfung auf Gleichheit
Die im Abschnitt Dezimalbrüche genannte Einschränkung, dass viele dieser Dezimalzahlen im Binärsystem eines Computers nicht genau dargestellt werden können, hat beim Programmieren Auswirkungen auf Vergleiche zwischen Gleitkommazahlen. Ein Beispiel in der Programmiersprache C soll dies verdeutlichen:
#include <stdio.h>
int main(void) {
if (0.362 * 100.0 != 36.2)
puts("verschieden"); <span title="Aus: Deutsche Wikipedia, Abschnitt "Prüfung auf Gleichheit"" class="plainlinks">[https://de.wikipedia.org/wiki/Gleitkommazahl#Prüfung_auf_Gleichheit <span style="color:#dddddd">ⓘ</span>]</span>
if (0.362 * 100.0 / 100.0 != 0.362)
puts("auch verschieden");
return 0;
}
Obwohl die beiden Gleichungen und mathematisch korrekt sind, werden sie wegen der ungenauen Umrechnung ins Computer-Binärsystem falsch. Im Beispiel-Programm werden somit beide Ungleichungen als wahr angesehen. ⓘ
Vergleiche müssen deshalb durch eine Abfrage ersetzt werden, ob die zu vergleichenden Werte im Rahmen einer erreichbaren Genauigkeit (meist Toleranz genannt) als gleich angesehen werden können. ⓘ
Toleriert man beim Vergleich einen absoluten Fehler, lautet eine mögliche Formulierung . ⓘ
Toleriert man beim Vergleich einen relativen Fehler, lautet eine mögliche Formulierung . Der zweite Fall muss meist noch mit der Sonderfallabfrage verbunden werden. ⓘ
Alternativ kann man alle Faktoren respektive Summanden inklusive des zu erwartenden Ergebnisses eben jener problematischen Vergleiche bei rationalen Gleitkommazahlen auch mit multiplizieren, wobei den Index der letzten Nachkommastelle angibt. Allgemeiner gesagt: Alle Gleitkommazahlen müssen – sofern möglich – in Brüche umgewandelt werden. Diese können wiederum eindeutig und ohne Rundungen der Mantisse in das binäre Zahlensystem konvertiert werden. Compiler mancher Programmiersprachen (z. B. Java, Ruby, C++, Objective-C, Swift, Rust usw.) können direkt mit den Brüchen rechnen und vergleichen die Brüche in den oben aufgeführten bedingten Anweisungen (If-Anweisungen), welche dadurch nicht betreten werden. Andere Programmiersprachen (z. B. Object Pascal, PHP, JavaScript, Perl, Python usw.) wiederum wandeln den Bruch bzw. den Quotient als allerersten Schritt wieder in eine Binärzahl um und vergleichen dann erst beide Werte, wodurch in dem Fall beide Bedingungen wahr sind und die oben angegebenen Ausgaben getätigt werden. ⓘ
Sogar Zahlen mit exakt denselben Bitmustern und somit eigentlich exakt identischen Werten werden vom Rechner mit manchmal nicht als gleich angesehen. Das hat als Ursache die manchmal nicht identischen Formate im Speicher (Bsp.: Intel 64 Bit) und während einer Rechnung in der Gleitpunkteinheit (Bsp.: Intel 80 Bit). Wenn dieselben Bitmuster, die verglichen werden sollen, einmal aus dem Speicher und somit gerundet und einmal aus der FPU und somit mit der vollen Genauigkeit kommen, führt ein Vergleich zum falschen Ergebnis. Die Abhilfe ist dieselbe wie schon beschrieben. Bei größer/kleiner Vergleichen kann dieses Problem auch auftauchen, je nach verwendeter Sprache und Architektur sind spezielle Befehle und/oder ein Umweg über den Arbeitsspeicher zu nehmen um dies zu lösen. ⓘ