Blog durchsuchen
Profil
Marcus Frenkel hat Informatik an der HTWK Leipzig studiert und versucht sich derzeit an wissenschaftlicher Arbeit und einer Promotion im gleichen Fach. Außerhalb der digitalen Welt musiziert er gern, ist begeisterter Sportler und Leser von Scheibenwelt-Romanen.
Letzte Einträge
- Datenmengen im großen Stil6 Kommentare· 17.05.12
- Künstliche neuronale Netze: Intelligenz im Computer - Teil 39 Kommentare· 20.04.12
- Simulierte Rechner im Rechner9 Kommentare· 02.04.12
- Künstliche neuronale Netze: Intelligenz im Computer - Teil 26 Kommentare· 24.03.12
- Künstliche neuronale Netze: Intelligenz im Computer - Teil 114 Kommentare· 15.03.12
Kommentare
- Silvio Haupt · 19.05.12 · 08:44 Uhr Datenmengen im großen Stil
- Quacki · 29.04.12 · 13:05 Uhr Künstliche neuronale Netze: Intelligenz im Computer - Teil 3
- ich hatte... · 20.04.12 · 22:04 Uhr Evolutionäre Algorithmen - Die Evolution als Vorbild zur Problemlösung - Teil 4
- Marcus Frenkel · 20.04.12 · 11:04 Uhr Künstliche neuronale Netze: Intelligenz im Computer - Teil 2
- Sepp · 06.04.12 · 20:24 Uhr Simulierte Rechner im Rechner
Blogroll
« vorheriger Beitrag · nächster Beitrag »
15.09.11 · 08:50 Uhr
Gleitkommazahlen: Warum Computer doch nicht so präzise rechnen - Teil 2
Kategorie: Naturwissenschaften · Kommentare: 8
So, hier endlich die Fortsetzung zum Thema "Rechnen mit Gleitkommazahlen". Das letzte mal habe ich erklärt, was Gleitkommazahlen überhaupt sind und wie sie im Computer dargestellt werden. Den Nachteil dieser Zahlendarstellung habe ich auch schon vorgestellt: es lassen sich nicht sämtliche Zahlen in einem bestimmten Bereich darstellen (was bei den reellen Zahlen ohnehin mit endlichem Speicher nicht möglich wäre); schlimmer noch ist aber, dass die Abstände zwischen den darstellbaren Zahlen immer größer werden, je größer die Zahlen selber werden. Tückisch wird das vor allem dann, wenn es ans Rechnen mit Gleitkommazahlen geht. Und das soll das heutige Thema sein.
Bevor die Probleme beim Rechnen dargelegt werden können, muss natürlich erst einmal geklärt werden, wie mit Gleitkommazahlen überhaupt gerechnet wird. Glücklicherweise ist das nicht allzu umständlich und lässt sich relativ schnell erklären. Insbesondere Multiplikation und Division lassen sich (in der Theorie) sehr einfach umsetzen; bei der Multiplikation werden einfach die beiden Mantissen (welche ja Festkommazahlen darstellen) miteinander multipliziert und die beiden Exponenten addiert. Wollen wir zum Beispiel die beiden Dezimal-Zahlen 2.5*105 und 6.1*103 miteinander multiplizieren, so rechnen wir:
2.5 * 6.1 = 15.25
und
5 + 3 = 8
Damit erhalten wir als Ergebnis 15.25*108, was in der Tat der gewünschten Zahl entspricht. Bei der Division kann man genauso vorgehen, nur dividiert man hier die Mantissen und subtrahiert die Exponenten. Im dualen Zahlensystem funktioniert die Rechnung genauso, kann also auch auf den Bitketten der bereits vorgestellten Gleitkommadarstellung im Computer durchgeführt werden - ich führe die weiteren Rechnung aber alle im Dezimalsystem aus, damit sie besser verständlich sind.
Für Addition und Subtraktion muss nur ein zusätzlicher Schritt durchgeführt werden: vor der eigentlichen Rechnung müssen die Exponenten angeglichen werden. Sollen also etwa die beiden oben genannten Zahlen 2.5*105 und 6.1*103 addiert werden, so muss die erste Zahl entweder als 250.0*103 oder die zweite als 0.061*105 umgeschrieben werden - üblicherweise transformiert man die kleinere Zahl hin zum größeren Exponenten. Anschließend reicht es, die beiden Mantissen zu addieren. Für obiges Beispiel ergibt sich damit die folgende Rechnung:
2.5*105 + 6.1*103 = 2.5*105 + 0.061*105 = 2.561*105
So weit, so einfach. Die Anpassung des Exponenten kann übrigens ziemlich einfach durchgeführt werden, indem das Komma der Mantisse um die benötigte Anzahl an Stellen nach links oder rechts geschoben wird (das geht im dualen wie im dezimalen System gleichermaßen).
Die Problematik entsteht dadurch, dass im Computer nur eine bestimmte Menge an Bits für eine Gleitkommazahl zur Verfügung stehen; insbesondere die beschränkte Mantissenlänge (für Gleitkommazahlen einfacher Genauigkeit sind das etwa 23 Bit) erweist sich hier als der größte Fallstrick mit verschiedenen Auswirkungen.
Eine dieser Auswirkungen ist die sogenannte Auslöschung (im Englischen cancellation genannt). Sie tritt auf, wenn bei der Verrechnung ähnlicher Zahlen niederwertige Informationen verloren gehen und sich dabei zwar nicht der absolute Fehler, dafür aber der relative Fehler erhöht. Als absoluten Fehler bezeichnet man die tatsächliche Abweichung einer (berechneten) Zahl vom eigentlich gewünschten Wert. Soll etwa das Ergebnis einer Rechnung den Wert 0.51 ergeben, der Computer errechnet aber stattdessen 0.50, so haben wir einen absoluten Fehler von 0.01. Berechnen wir 100.50, wollten aber 100.51, so ist der absolute Fehler ebenfalls 0.01. Der relative Fehler bezeichnet dementsprechend die relative Abweichung der beiden Werte (des berechneten und des eigentlich korrekten) voneinander. Beim Wertepaar 100.51/100.50 beträgt der relative Fehler (die relative Abweichung) knapp 0.01%, wohingegen es beim Wertepaar 0.51/0.50 bereits 2% Abweichung sind. Der Effekt tritt insbesondere bei der Subtraktion auf; ein Beispiel: angenommen, wir haben die Zahlen 1.2345*105 und 1.2340*105 und wollen sie voneinander subtrahieren. In der "gewöhnlichen" Mathematik ist das kein Problem und wir erhalten als Ergebnis:
1.2345*105
- 1.2340*105
____________
= 0.0005*105
Rechnen wir nun aber am Computer, so ist ja die maximale Anzahl an speicherbaren Ziffern in einer Zahl beschränkt; stehen uns zum Beispiel nur 4 Ziffern zur Verfügung (im binären System würde das 4 Bit entsprechen), so würden statt der originalen Zahlen gerundete verwendet werden. Wir hätten also die folgende Rechnung:
1.235*105
- 1.234*105
___________
= 0.001*105
Man sieht, dass der absolute Fehler bei der ersten (gerundeten) Ausgangszahl und dem (demzufolge inkorrekt berechneten) Ergebnis jeweils gleich ist, nämlich 0.0005*105. Der relative Fehler jedoch ändert sich dramatisch, von lächerlichen 0.04% (1.2345 zu 1.235) auf gewaltige 50% (0.0005 zu 0.001)! Man kann sich einfach vorstellen, dass derartige Abweichungen schnell zu vollkommen falschen Ergebnissen führen können, wenn nämlich mehrere Berechnungen nacheinander ausgeführt werden, wobei die (Zwischen-)Ergebnisse vorhergehender Rechnungen als Werte in die nächste Rechnung mit eingehen.
Doch damit nicht genug: auch bei der Verrechnung von Zahlen sehr unterschiedlicher Größe kann es zu einem Fehler kommen, der sogenannten Absorption. Sie hat die gleiche Ursache wie die Auslöschung, nämlich die beschränkte Anzahl an Mantissenstellen. Zur Absorption kann es kommen, wenn der Exponent einer sehr kleinen Zahl an den einer sehr großen Zahl angepasst wird und dabei viele oder sämtliche signifikanten Mantissenziffern verloren gehen. Auch hierfür ein kurzes Beispiel: nehmen wir die Zahlen 1.0*105 und 1.5*102, welche wir addieren wollen (wobei wir weiterhin 4 Ziffern für die Mantisse speichern können). Für die Addition muss der Exponent der zweiten Zahl angepasst werden; man würde sie also folgendermaßen umschreiben:
1.5*102 = 0.0015*105
Da wir aber nur 4 Ziffern speichern können, ergibt sich stattdessen die Zahl
0.001*105. Führen wir nun die Addition aus, ergibt sich statt der korrekten Rechnung
1.0000*105
+ 0.0015*105
___________
= 1.0015*105
die nicht akkurate Rechnung
1.000*105
+ 0.001*105
___________
= 1.001*105
Durch die Rundung haben wir also ein inkorrektes Ergebnis erhalten. Dies kann sogar so weit führen, dass bei hinreichend großem Unterschied in den Exponenten die zweite Zahl überhaupt keinen Beitrag mehr zur Rechnung hat, wenn nämlich sämtliche Signifikanten Ziffern bei der Anpassung des Exponenten verloren gehen. Glücklicherweise tritt dieses Problem nur bei der Addition und Subtraktion auf, da bei Multiplikation und Division keine Anpassung des Exponenten und damit kein Verlust von Mantissenziffern stattfindet.
Zusätzlich können die Auswirkungen dieses Effekts durch geschicktes Rechnen vermindert werden. Angenommen, zu einer sehr großen Zahl sollen viele sehr kleine Zahlen addiert werden. Führt man die Rechnung in der üblichen Art und Weise durch (indem man die ganzen kleinen Zahlen auf die große addiert), erhält man am Ende unter Umständen ein falsches Ergebnis, da sämtliche Ziffern der kleinen Zahlen bei der Addition verloren gegangen sind. Addiert man dagegen zuerst die kleinen Zahlen miteinander und verrechnet dieses Ergebnis erst mit der großen Zahl, kann man das Glück haben, dass die Addition der kleinen Zahlen ein genügend großes Ergebnis ergibt, dass es bei der Addition mit der großen Zahl noch einen Einfluss auf die Rechnung hat.
Die beiden vorgestellten Effekte ziehen noch einen weiteren nach sich, nämlich, dass das aus der Mathematik bekannte Assoziativ- und das Distributivgesetz im Bereich der Gleitkommazahlen am Computer nicht mehr gelten. Wir erinnern uns: das Assoziativgesetz sagt aus, dass (a+b)+c = a+(b+c) gelten soll (auf deutsch, dass es egal ist, welche Bestandteile einer Summe zuerst miteinander addiert werden). Gerade eben haben wir aber gesehen, dass gerade das aber bei Gleitkommazahlen nicht gilt, da es durchaus relevant ist, ob man zuerst Zahlen gleicher Größenordnung oder zuerst Zahlen unterschiedlicher Größenordnung miteinander verrechnet. Das Distributivgesetz besagt, dass a*(b+c) = (a*b)+(a*c) gelten soll, was auf Grund der eben genannten Problematik bei Gleitkommazahlen leider auch nicht uneingeschränkt gilt.
All die genannten Probleme zeigen, dass das Rechnen mit Gleitkommazahlen am Computer nicht ganz einfach ist. Insbesondere in Bereichen mit vielen Berechnungen müssen sich die Programmierer einer Anwendung daher genaue Gedanken darüber machen, wie und in welcher Reihenfolge sie ihre Berechnungen durchführen. Allein die Änderung der Berechnungsreihenfolge kann da schon zu erheblichen Verbesserungen führen; manchmal sind aber auch neue oder abgewandelte Formeln notwendig, um die gröbsten Probleme bei der Berechnung zu umgehen. In Umgebungen, wo allerhöchste Präzision gefragt ist, ist das natürlich keine Lösung; hier würde der Programmierer dann auf andere Methoden der Zahlendarstellung zurückgreifen (die so viele Bits für eine Zahl zur Verfügung stellen, wie benötigt werden - die aber auch nicht mehr einfach so von der CPU verarbeitet werden können).
Autor: Marcus Frenkel· 8 Kommentare· Permalink· Trackback-URL
Kommentar schreiben
Top5
- Liebe Piraten, lasst uns endlich vernünftig miteinander reden!Astrodicticum Simplex· 14.05.2012
- Risikowahrnehmung: Wenn man vor den falschen Dingen Angst hatAstrodicticum Simplex· 20.05.2012
- Dr. h.c. im Sonderangebot für 39 Euro[sic]· 14.05.2012
- Pi auf dem Einrad!Astrodicticum Simplex· 20.05.2012
- Die Erde dreht sich nicht um die Sonne...Astrodicticum Simplex· 12.05.2012
Top5
- Liebe Piraten, lasst uns endlich vernünftig miteinander reden!Astrodicticum Simplex· 14.05.2012
- Klimaschmock des Monats Mai 2012Primaklima· 20.05.2012
- Die kalte Sonne von Vahrenholt/Lüning: Le Trend, c'est moi!Primaklima· 16.05.2012
- Risikowahrnehmung: Wenn man vor den falschen Dingen Angst hatAstrodicticum Simplex· 20.05.2012
- Der NRW Wahlkampf - eine Analyse mit Noten.Primaklima· 14.05.2012
ScienceBlogs.com
- Doubt and other products: The National Toxicology Program's Report on Carcinogens, bad for whose business?by Elizabeth Grossman As it pursues its anti-regulatory agenda the ...The Pump Handle· 22.05.2012 · 16:39 Uhr
- Weekend Recap: My Annular Eclipse Expedition!A little more persistence a little more effort and what ...Starts With A Bang· 22.05.2012 · 00:11 Uhr
- Water, waterThis image has been going around the intertubes recently I ...A Few Things Ill Considered· 21.05.2012 · 22:59 Uhr
- To be or not to be? The Prevention and Public Health Fundby Kim Krisberg We will pay for this by taking ...The Pump Handle· 21.05.2012 · 15:19 Uhr
- An important revelation regarding Heartland Gate (global warming denialism)Peter Gleick has been cleared of faking a key memo ...Greg Laden's Blog· 21.05.2012 · 12:52 Uhr

Kommentare (8)
Imho macht jeder Programmierer irgendwann die erhellende Erfahrung, daß es eben nicht egal ist, was in welcher Reihenfolge gerechnet wird. Ganz besonders bei Algorithmen, die in winzigsten Schritten von einem Wert zum nächsten hüpfen - bei mir wars vor langen Jahren ein Programm, das die Lösung mittels ballistischer numerischer Integration zu finden suchte. Und bei der Wahl der Randbedingungen für den nächsten Versuch eigentlich nur im Nebel stocherte, da die erste Runge-Kutta-Implementierung die Besonderheiten des Modells eben nicht berücksichtigte.
exzellenter Artikel, vielen Dank.
Als Ergänzung zu deinen Ausführungen sei noch ein komplexeres Beispiel erwähnt: die Berechnung der Nullstellen einer quadratischen Funktion.
Mathematisch liegen diese ja bei x1/2 = ( -b +/- wurzel(b^2-4ac) ) / 2a
Durch das Quadrat wird b innerhalb der Klammer aber gerne mal zu klein oder groß, wodurch Genauigkeitsverluste entstehen (bzw. im Extremfall die Wurzel imaginär wird). Viel gravierender ist aber der nicht unübliche Fall, dass a, b und c in ähnlicher Größenordnung liegen. Dann kann es passieren, dass b^2 gegenüber 4ac genügend groß wird, dass die Auslöschung greift und wurzel(b^2-4ac) ungefähr b wird. Hups :D
Mit einer abgewandelten - komplexeren - Formel lässt sich das aber in den Griff bekommen.
Ein berühmter Programmierfehler ist auch, mit Gleitkomma zu rechnen (ggf. implizit bei automatischer Typkonvertierung, z.B. weil ein Zwischenergebnis nicht mehr in ein double passt) und dann auf Gleichheit zu testen. Hat auch mir schon manche Stunde Freude gemacht....
Der Vollständigkeit halber (wer sich die blutigen Details gönnen will...) sei http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html erwähnt.
noch was: wenn man sich endlich an Rundungsfehler gewöhnt hat kann einem auch das hier passieren....
http://www.xkcd.com/217/
mal was anderes, ich lese dich nämlich echt gerne, aber was nervt ist das der rss feed nicht funzt. kthxbye
@berti
Das liegt dann aber nicht an mir...;)
Mein RSS-Feed geht für ganz SB.de, inklusive meines Blogges. Vielleicht einmal die Einstellungen überprüfen?
Keine Ahnung welchen er meint, doch die beiden sind unterschiedlich: Im globalen thread-feed tauchen Deine posts auf, aber im globalen comment-feed nicht die dazu gehörenden Kommentare (lokale feeds nutze ich nicht).
So bleibt nur zu-Fuß-abonnieren mit einem Kommentar/Artikel. Und selbst das muß ich bei Interesse manchmal ein zweites Mal unternehmen, was dann allerdings nicht mit der 'üblichen' nick-mail-combi funktioniert. Zum Abschluß die gute Nachricht: Dreimal war noch nie nötig ;-)
btw: Eben beim Nachschauen stellte ich fest, daß dies blog zwar im Blog-Index, nicht aber in der rss-Liste der blogs auftaucht. Vielleicht ist dieser Lapsus dafür verantwortlich oder läßt zumindest auf eine gemeinsame Ursache schließen...
Hmmm...da muss ich die zuständige Person dafür mal nerven. Danke für den Hinweis.
ooops, etwas Wichtiges zur Präzisierung fehlt: Der Bedarf an 'Nachabonnieren' besteht blogunabhängig auf ganz SB.de, nicht etwa ausschließlich bei Bits&Bytes. Obgleich, eine Strichliste habe ich nicht geführt...