Programmiertechnik/Rechnerarithmetik

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Informationen zum Autor

Name:
Janosch Zoller
E-Mail:
Homepage:

Stellt man mithilfe eines Computerprogramms oder beim Programmieren in einer beliebigen Programmiersprache numerische Berechnungen an, so erhält man gelegentlich verblüffende Ergebnisse - beispielsweise treten oft unerwartet Rundungsfehler auf. Während man in der Praxis in vielen Fällen über diese Rundungsfehler hinwegsehen kann, erreicht man gelegentlich doch einen Punkt, an dem man entweder auf entsprechend genaue Berechnungen angewiesen ist oder die Rundungsfehler durch Verwendung entsprechend großer Zahlen auf einmal wieder an Bedeutung gewinnen. An dieser Stelle ist es dann wichtig zu wissen, durch welche Effekte diese Fehler oder Ungenauigkeiten zustande kommen, um sie beheben, ausgleichen, oder umgehen zu können - und auch schon in der Fehlersuche kann das Wissen über die Existenz solche Effekte erheblich Zeit sparen.

Dieser Artikel soll die verschiedenen Effekte, die in der Rechnerarithmetik - also dem computergestützten Rechnen - auftreten können, nennen und ihr Zustandekommen erklären. Die Häufigkeit und Schwere, mit der die einzelnen Effekte zum Tragen kommen, hängt dabei nicht zuletzt auch von der verwendeten Programmiersprache ab, da die Art, in der Zahlen gespeichert und verarbeitet werden, einen großen Einfluss auf die entsprechenden Effekte hat. Dennoch werden die besprochenen Effekte - aus Gründen der Performance - in den meisten Programmiersprachen nicht immer von Haus aus ausgeglichen, selbst wenn das mit entsprechendem Aufwand möglich wäre.

Inhaltsverzeichnis

[Bearbeiten] Nicht exakt darstellbare Zahlen

Beispiel: Motivation - Effekt in JavaScript ansehen …
<body>
    <h1>Rundungsfehler in JavaScript</h1>
    <main>
        <p>Schon einfache Berechnungen mit JavaScript können Rundungsfehler aufweisen:</p>
        <p><input type="text" value="0.1 + 0.2 + 0.3"><input type="button" value="berechnen!"></p>
    </main>
</body>
<script>
    window.addEventListener("load",function(e) {
        document.querySelector("input[type=button]").addEventListener("click",function(e) {
            var input = document.querySelector("input[type=text]");
            input.value = eval(input.value);
        });
    });
 
    //window.alert(0.1+0.2+0.3);
    //Ergebnis: 0.6000000000000001
</script>
Beobachtung: Schon bei einer "einfachen" Rechnung ergeben sich sichtbare Rundungsfehler - woher kommen die Rundungsfehler, wenn die eingegebenen Zahlen exakt waren?

Das Konzept nicht exakt darstellbarer Zahlen ist uns eigentlich schon aus der Schulmathematik wohlbekannt und kommt immer dann zum Tragen, wenn man über den Bereich der ganzen Zahlen hinausgeht. Man denke beispielsweise an irrationale Zahlen - es gibt keine Möglichkeit, √2 mit einer Dezimalzahl exakt darzustellen.

Und während das Beispiel der irrationalen Zahlen nicht nur das Dezimalsystem betrifft, in dem wir Menschen gewöhnlich rechnen und denken, sondern Zahlensysteme jeder Basis, so gibt es auch rationale Zahlen, die in manchen Zahlensystemen mit endlich vielen Ziffern exakt darstellbar sind und in anderen nicht - wir sagen dann in letzterem Fall, dass solche Zahlen eine periodische Darstellung besitzen.

Beispiel: Eine periodische Zahl im Dezimalsystem
1/3 = 0,310 ≈ 0,333310
Hier und in allen weiteren Beispielen in diesem Artikel gibt die kleingestellte Zahl hinter einer gebrochenen Zahl die Basis des verwendeten Zahlensystems an - in diesem Fall also die 10 für das Dezimalsystem. Der Strich über den letzten Ziffern bedeutet eine unendliche periodische Fortsetzung der entsprechenden Ziffern. Eine Darstellung mit endlich vielen Ziffern ist nicht exakt und Ergebnis einer Rundung.

Hinweis

In den Texten dieses Artikels kommt häufig die Bezeichnung gebrochene Zahl vor. Gemeint ist damit die Art von Zahlendarstellung, die wir normal - im Dezimalsystem - als Dezimalzahl oder Dezimalbruch bezeichnen, also eine Zahl mit Komma in der Darstellung. Da sich dieser Artikel auch auf Zahldarstellungen in anderen Zahlensystemen bezieht, wurde statt der Bezeichnung Dezimalzahl die allgemeinere Bezeichnung gebrochene Zahl gewählt. Bezogen auf die technische Repräsentation spricht man auch oft von Fließkommazahlen bzw. Gleitkomma-/Gleitpunktzahlen, meint damit aber eher eine besondere Art der Speicherung, wie sie in allen Programmiersprachen für gebrochene Zahlen üblich ist.

Bevor wir nun auf die Eigenheiten des im Rechner intern verwendeten Binärsystems eingehen können, müssen wir noch einen kleinen Exkurs einschieben - das folgende Unterkapitel kann von fortgeschrittenen Lesern, die sich mit der Darstellung gebrochener Zahlen in beliebigen Zahlensystemen auskennen, natürlich übersprungen werden.

[Bearbeiten] Gebrochene Zahlen in beliebigen Zahlensystemen

Wir sind es gewohnt, mit gebrochenen Zahlen im Dezimalsystem umzugehen. Tatsächlich sind wir den Umgang damit derart gewohnt, dass wir nicht bewusst bemerken, was genau hinter der Darstellung steht - was das Verständnis von gebrochenen Zahlen in anderen Zahlensystemen erschwert. Aus der Grundschule kennt man die Benennung der Ziffern einer ganzen Zahl als Einer, Zehner, Hunderter - und ganz analog lassen sich die Nachkommastellen als Zehntel, Hundertstel, Tausendstel auffassen. Man kann damit jede Dezimalzahl in eine Summe von Vielfachen der Basis 10 und ihrer Potenzen zerlegen (in der Mathematik spricht man bei einer solchen Darstellung von einem 10-adischen Bruch).

Beispiel: Darstellung einer Dezimalzahl als 10-adischer Bruch
123,54610 = 1 * 102 + 2 * 101 + 3 * 100 + 5 * 10-1 + 4 * 10-2 + 6 * 10-3

Führt man sich diesen Zusammenhang vor Augen, so lässt sich die Bedeutung einer gebrochenen Zahl im Binärsystem ganz einfach analog erklären - auch hier gibt es eine entsprechende Darstellung in Form eines 2-adischen Bruchs.

Beispiel: Darstellung einer Binärzahl als 2-adischer Bruch
110,1012 = 1 * 22 + 1 * 21 + 0 * 20 + 1 * 2-1 + 0 * 2-2 + 1 * 2-3
         = 4 + 2 + 0 + 1/4 + 0 + 1/16 = 6,312510

Das erklärt auch die Antwort auf die Frage, in welchem Zahlensystem es eine exakte Darstellung von 1/3 mit endlich vielen Ziffern gibt.

Beispiel: "Periodische Zahl" mit endlich vielen Ziffern in anderem Zahlensystem
0,310 = 1/3 = 1 * 3-1 = 0,13
Im Dreier-System kann die rationale Zahl 1/3 mit endlich vielen Nachkommastellen dargestellt werden - im Dezimalsystem nicht.

[Bearbeiten] Nicht exakt darstellbare Zahlen im Binärsystem

Das Binärsystem ist bekannterweise die Form, in der Computer Zahlen speichern und verarbeiten. Im Gegensatz dazu verwendet der Anwender - und meist auch der Programmierer - zur Eingabe von Zahlen das Dezimalsystem. Das kann schon bei scheinbar unbedenklichen Zahlen zu Problemen führen. Die einfachsten gebrochenen Zahlen, die sich der Anwender vorstellen kann, sind die Potenzen der Dezimalbasis - also Zahlen wie 0,1 oder 0,001. Diese Zahlen stellen den Computer vor unlösbare Schwierigkeiten - denn sie sind im Binärsystem, also mit Potenzen von 2, nicht exakt mit endlich vielen Ziffern darstellbar.

Beispiel: Einfache Dezimalzahlen sind im Binärsystem periodisch
0,110 = 0,000112

Leider ist der Computer aber nicht in der Lage, unendlich viele Ziffern zu speichern oder zu verarbeiten - die Ziffernfolge muss also ab einer bestimmten Länge (abhängig von Programmiersprache und System) abgeschnitten werden. Daraus ergibt sich der eingangs gezeigte Rundungsfehler.

Beispiel: Rundungsfehler beim Abschneiden einer periodischen Zahl
0,000112 = 0,0937510
Rundungsfehler bei Speicherung einer "exakten" Dezimalzahl im Binärformat, angenommen es wären lediglich die ersten 5 Nachkommastellen durch den Computer speicherbar. Die scheinbar unbedeutende Änderung im Binärsystem (es wird nach "nur" 5 Stellen abgeschnitten) hat im Dezimalsystem deutlich spürbare Auswirkungen.

Das Beispiel zeigt auch, dass schon einfachste Dezimalzahlen im Binärsystem relativ viele Stellen benötigen, um auch nur einigermaßen exakt zu sein. Die maximale Präzision, die mit Fließkommazahlen erreicht werden kann, wird dabei durch die Programmiersprache und - mit entsprechender Typisierung - durch den gewählten Datentyp festgelegt. So sind zum Beispiel die Datentypen float (32 Bit) und double (64 Bit) üblich. Diese Datentypen speichern die Zahlen in einer standardisierten Darstellung (IEEE 754) und können dann noch 23+1 bzw. 52+1 Bit für tatsächlich zählende Ziffern aufbringen. Auch das kann bei scheinbar einfachen Zahlen zu spürbaren Rundungsfehlern führen.

Beispiel: Gesteigerter Ziffernbedarf im Binärsystem
6,000110 ≈ 110,0000000001000001100012 = 6,00099992752...10
Typische Präzision einer float-Fließkommazahl - Es stehen 23 Ziffern und eine führende 1, also insgesamt 24 Ziffern zur binären Speicherung zur Verfügung. Schon bei für den Anwender einfach vorstellbaren Zahlen ist damit ein Präzisionsverlust deutlich spürbar.

Viele Programmiersprachen versuchen, diesen Effekten entgegen zu wirken. So ist heutzutage in vielen Sprachen die double precision das Standardformat für Fließkommazahlen. Bei entsprechendem Abstraktionsgrad der verwendeten Programmiersprache werden gelegentlich auch zusätzliche Techniken eingesetzt, um Rundungsfehler zu vermeiden. Diese sind allerdings nicht unfehlbar - und man muss sich jederzeit im Klaren darüber sein, dass in Endergebnissen falsch gerundete Stellen vorkommen können, deren Ursachen in der Binärdarstellung liegen.

Beispiel: Verschiedene Rundung bei unterschiedlichen Eingangszahlen
window.alert(0.1+0.2+0.3);

//Ergebnis: 0.6000000000000001

window.alert(0.1+0.1+0.1+0.1+0.1+0.1);

//Ergebnis: 0.6

window.alert(0.2+0.2+0.2);

//Ergebnis: 0.6000000000000001

window.alert(0.3+0.3);

//Ergebnis: 0.6
Beobachtung: Das Vorkommen von darstellungsbedingten Rundungsfehlern ist kaum zweifelsfrei vorherzusagen.

Hinweis

Es gibt auch Software, die exakt rechnet: sogenannte Computeralgebrasysteme (CAS) verzichten auf eine Speicherung wie hier beschrieben und nutzen stattdessen, ähnlich wie Menschen, algebraische Umformungen und Rechenregeln zur Ermittlung exakter Ergebnisse. Eine solche Behandlung ist allerdings aufwändig und verhältnismäßig ressourcenhungrig, weshalb sie nur dort zur Anwendung kommt, wo sie explizit benötigt wird.

[Bearbeiten] Datentyp-basierte Effekte

Im vorigen Abschnitt wurden Zahlen besprochen, die für den Computer nicht exakt binär darstellbar sind. Tatsächlich kommen aber auch bei exakt binär darstellbaren Zahlen problematische Effekte vor - meist bedingt durch Eigenheiten des Datentyps, mit dem die entsprechenden Zahlen gespeichert werden. Wir befassen uns in diesem Abschnitt also, um den Unterschied noch einmal klar zu machen, nicht mehr primär mit gebrochenen Zahlen, sondern insbesondere auch mit ganzen Zahlen.

Grundsätzlich sind Datentypen zunächst einmal immer durch den zur Verfügung stehenden Speicherplatz limitiert. Lange Zeit waren Datentypen mit 32 Bit die Standard-Datentypen in den meisten Programmiersprachen (Java: Stichworte int, float), inzwischen wird, mit zunehmender Verbreitung von 64-Bit-Prozessoren und insgesamt verringertem Speichermangel oft auf 64 Bit für Standard-Datentypen gesetzt (Java: Stichworte long, double).

Dabei unterscheidet man weiterhin zwischen der Speicherung als Fließkommazahl oder als Festkommazahl. Die einfachsten Beispiele für Festkommazahlen sind die gewöhnlichen ganzen Zahlen - und die korrespondierenden Ganzzahl-Datentypen (Java: int, long). Diese Ganzzahl-Datentypen - und allgemein alle Festkommazahl-Datentypen - zeichnen sich dadurch aus, dass sie (je nach dem ihnen zur Verfügung stehenden Speicherplatz) nur ganz bestimmte Wertebereiche besitzen. Festkommazahlen sind also nicht primär durch die Anzahl zählender Ziffern begrenzt, sondern vielmehr durch den zugeordneten Wertebereich. Der Wertebereich einer gewöhnlichen 32-Bit-Festkommazahl umfasst etwa 4,3 Milliarden verschiedene Zahlen.

Die Speicherung einer Fließkommazahl wurde im vorhergehenden Abschnitt schon angerissen. Der Standard IEEE 754 definiert dabei, wie die einer Fließkommazahl zur Verfügung stehenden Bits zur Speicherung der entsprechenden Zahl verwendet werden. Dabei entfällt ein Teil der Bits auf die sogenannte Mantisse, also den Teil der Zahl, der die zählenden Ziffern (binär) darstellt. Ein weiterer Teil der Bits entfällt auf den sogenannten Exponenten - vergleichbar mit dem Exponenten von 10, wenn man eine Dezimalzahl in wissenschaftlicher Schreibweise darstellt. Bei einer Zahl in single precision (float) wären das beispielsweise 23 Bit für die Mantisse und 8 Bit für den Exponenten (das letzte "fehlende Bit" entfällt auf das Vorzeichen). Eine Fließkommazahl wird daher von zwei Seiten limitiert - einerseits durch die maximale Anzahl zählender Ziffern (Mantisse), andererseits durch den maximalen Wertebereich des Exponenten (dieser gibt quasi die Größenordnung der Zahl an). Trotz dieser doppelten Limitierung sind Fließkommazahlen durch die Kombination aus Mantisse und Exponent in ihrem Wertebereich deutlich flexibler als Gleitkommazahlen - der Wertebereich einer single precision-Fließkommazahl erstreckt sich bei beiden Vorzeichen zwischen den Größenordnungen 10-45 und 1038!

In vielen Programmiersprachen hat der Programmierer Kontrolle über die Wahl des Datentyps, mit dem er arbeiten möchte. Je nachdem kann man schon vorher abschätzen, ob der Eine oder der Andere der hier genannten Effekte auftreten wird und ob dadurch Probleme drohen; der Datentyp kann dann situationsangepasst gewählt werden. Diese Möglichkeit entfällt in Sprachen mit sehr hohem Abstraktionsniveau (wie beispielsweise JavaScript), da die entsprechende Programmiersprache die Wahl des Datentyps übernimmt und zur Laufzeit gegebenenfalls auch dynamisch anpasst. In solchen Sprachen ist es dann oft auch schwieriger, den einen oder anderen Effekt zu kontrollieren oder vorherzusagen.

[Bearbeiten] Fließkomma-Addition von Zahlen ungleicher Größenordnung

Beispiel: Addition ungleicher Zahlen in JavaScript
window.alert(5e+20 + 1);
//Ergebnis: 500000000000000000000
window.alert(5e+20 + 123456789);
//Ergebnis: 500000000000123500000
Beobachtung: Bei der Addition von Fließkommazahlen ganz unterschiedlicher Größenordnung kann es vorkommen, dass die kleinere Zahl im Ergebnis verschwindet - oder ein Teil davon.

Dieser Effekt ist - auch in seiner Begründung - ganz ähnlich zum letzten besprochenen Effekt im ersten Abschnitt. Grund für dieses unpräzise Ergebnis ist die Limitierung der Mantisse - also der Anzahl zählender Ziffern - in der Fließkommadarstellung. Sobald die zählenden Ziffern nicht mehr ausreichen, um die gesamte Zahl darzustellen, muss am Ende gerundet werden - zu Ungunsten etwaiger deutlich kleinerer Zahlen, die soeben aufaddiert wurden. Selbstverständlich ist auch die Subtraktion von dieser Problematik betroffen.

Tatsächlich ist es so, dass die Fließkommadarstellung zwar einen größeren Wertebereich hat, dieser jedoch ist deutlich weniger dicht mit möglichen Werten besetzt, als es in einer Festkommadarstellung der Fall wäre. Oder kurz und prägnant: Nicht jede ganze Zahl innerhalb des Wertebereichs einer Fließkommadarstellung ist darin auch tatsächlich darstellbar. Die Dichte der darstellbaren Ganzzahlen nimmt dabei mit größer werdendem Exponenten deutlich (sogar exponentiell) ab.

[Bearbeiten] Arithmetischer Unterlauf

Der arithmetische Unterlauf ist ein Effekt, der bei der Verwendung von Fließkommazahlen auftritt. Der Effekt tritt immer dann auf, wenn eine Zahl, die als Fließkommazahl gespeichert werden soll, betragsmäßig kleiner ist als die kleinste darstellbare Zahl im entsprechenden Datentyp. Der Wert der Zahl wird dabei grundsätzlich auf 0 gerundet; je nach Programmiersprache und Umgebung kann ein arithmetischer Unterlauf auch zu einer sichtbaren Warnung oder einem Fehler führen.

[Bearbeiten] Arithmetischer Überlauf

Festkommazahlen können im Allgemeinen positiv und negativ sein. Da ein Computer kein Vorzeichen, sondern eben nur Nullen und Einsen speichern kann, muss die interne Repräsentation von negativen Festkommazahlen durch positive erfolgen. Dabei hat sich aus technischen Gründen das sogenannte Zweierkomplement durchgesetzt, d.h. man erhält eine negative Zahl aus der entsprechenden positiven Zahl, indem man ihre Bits invertiert (Nullen in Einsen verwandeln und umgekehrt) und dann 1 addiert (die Überträge beim Addieren, die über die feste Anzahl verfügbarer Bits hinausgehen, werden ignoriert). Dadurch bekommt das höchstwertige Bit (die Stelle ganz links) eine Art Vorzeichenfunktion (negative Zahlen haben im höchstwertigen Bit eine 1, positive eine 0).

Beispiel: Bilden des Zweierkomplements bei 4-Bit-Binärzahlen
01012 = 510
     0101            1010
inv. ----          + 0001
     1010          ------
                     1011
10112 = -510
Bilden des Zweierkomplements der Binärdarstellung der Zahl 5, bei einer angenommenen Speicherkapazität von 4 Bit.

Arithmetischer Überlauf ist vor allem dafür bekannt, bei Festkommazahlen aufzutreten. Zwar ist dieser Effekt auch bei Gleitkommazahlen prinzipiell möglich, dort aber weit weniger üblich und wird oft auch durch andere Behandlung (z.B. dem Wert positive infinity im IEEE 754) verhindert. Arithmetischer Überlauf tritt dann auf, wenn das Ergebnis einer Berechnung nicht mehr innerhalb des festgelegten Wertebereichs liegt. Tatsächlich beginnen in der Binärdarstellung direkt nach den positiven Zahlen des Wertebereichs die negativen Zahlen desselben Wertebereichs, wie man sich durch Bilden der Zweierkomplemente klarmachen kann.

Beispiel: Anordnung der Zahlen im Zweierkomplement bei 4-Bit-Binärzahlen
00002 = 010
00012 =  110

01012 =  510
01102 =  610
01112 =  710
10002 = -810
10012 = -710
10102 = -610
10112 = -510

11112 = -110
In der Zweierkomplement-Darstellung sind die Binärzahlen, die negative Zahlen repräsentieren, größer als die Binärzahlen, die positive Zahlen repräsentieren. Per Definition ist grundsätzlich die kleinste darstellbare Zahl betragsmäßig größer als die größte darstellbare Zahl; in diesem Fall sind die Zahlen -8 und 7 die Grenzen des 4-Bit-Wertebereichs.

Dieser Umstand zeigt also schon ganz klar, welches Ergebnis man erhalten wird, wenn man über den (positiven) Wertebereich hinaus addiert: Eine negative Zahl.

Beispiel: Addition mit arithmetischem Überlauf bei 4-Bit-Binärzahlen
01012 = 510
01102 = 610
  0101
+ 0110
------
  1011
10112 = -510

Beim Subtrahieren mit Ergebnis unterhalb der unteren Grenze des Wertebereichs ergibt sich natürlich der analoge Effekt - auf die kleinstmöglich darstellbare Zahl folgt die größtmöglich darstellbare Zahl.

Selbstverständlich ist auch hier die Behandlung eines arithmetischen Überlaufs wieder Sache der verwendeten Programmiersprache oder des Programmierers - so ist es möglich, dass eine Programmiersprache entweder keine Überläufe zulässt, oder aber bei Vorkommen von Überläufen entsprechend warnt. Grundsätzlich gilt: Sofern der Programmierer einen Einfluss auf die Wahl des Datentyps hat, sollte dieser so gewählt werden, dass im zu erwartenden Betriebszustand nie ein Überlauf auftreten kann. Mögliche arithmetische Überläufe stellen weiterhin oft sicherheitsrelevante Probleme in fertigen Systemen dar, sofern deren Auftreten nicht vorher bedacht und behandelt wurde.

[Bearbeiten] Numerische Effekte

Während wir Menschen es im mathematischen Umfeld gewohnt sind, algebraisch, also mit Symbolen und Rechenregeln, zu rechnen, und dabei höchstens im Endergebnis runden zu müssen, gehen Computerberechnungen meist auf numerische Rechnungen zurück, in denen Zahlen in ihrer endlichen Repräsentation verwendet werden. Auch hier gibt es Effekte, die - über die bisher behandelten darstellungsbedingten Genauigkeitsverluste hinaus - in unerwarteter Weise auftreten können.

[Bearbeiten] Auslöschung

Dieser Effekt, auch geläufig unter seiner englischen Bezeichnung, cancellation, bezeichnet in der Numerik einen Genauigkeitsverlust bei der Subtraktion ähnlich großer Gleitkommazahlen. Man geht dabei davon aus, dass beide an der Subtraktion beteiligten Ausgangszahlen schon mit Rundungsfehlern behaftet sind. Im Umgang mit Computerberechnungen ist das - als Folge der Zusammenhänge aus dem vorigen Abschnitt - auch grundsätzlich der Fall. Der Effekt tritt also nicht direkt in Folge dessen auf, dass ein Computer die Berechnungen ungenau durchführt, sondern vielmehr da bei entsprechend fehlerbehaftet gespeicherten Werten gar keine genauere Berechnung mehr möglich ist.

Beispiel: Auslöschung
1,23456789 - 1,23467895 = -0,0011106
1,2345 - 1,2346 = -0,001
Die erste Zeile zeigt die Subtraktion zweier fast gleich großer Fließkommazahlen - die aber nur in den ersten vier Ziffern nicht fehlerbehaftet sind. Die zweite Zeile zeigt die selbe Rechnung, allerdings dieses Mal mit Zahlen, die nicht fehlerbehaftet sind. Während es logisch erscheint, mit den Zahlen, die (trotz Rundungsfehler) gespeichert sind zu rechnen, ergibt sich dadurch in diesem Beispiel eine Abweichung von 11% zwischen dem Ergebnis der exakten, um Rundungsfehler bereinigten Rechnung und der vermeintlich korrekten, logisch erscheinenden Berechnung - und das obwohl die relativen Fehler der Eingangszahlen im Bereich eines hundertstel Prozents lagen. Der relative Fehler hat sich also in einer Operation etwa um den Faktor 1000 vergrößert.

Der Name Auslöschung bezieht sich darauf, dass die Anzahl korrekter Stellen bei einer solchen Berechnung drastisch verringert wird - waren vor der Rechnung noch die Hälfte der zählenden Ziffern korrekt und nicht von Rundungsfehlern beeinflusst, so ist nach der Berechnung der Anteil von fehlerbehafteten Stellen deutlich höher. Insbesondere steigt damit auch bei jeder solchen Operation der relative Fehler sprunghaft an, wenn man die relativen Fehler der Eingangszahlen mit den relativen Fehlern der Ausgangszahlen vergleicht.

Besonders heimtückisch ist dieser Effekt dann, wenn man die zu verrechnenden Zahlen vorher nicht sieht, da mit Variablen gerechnet wird - und man dementsprechend auch auf den Rundungsfehler nicht aufmerksam wird.

Beispiel: Auslöschung bei Variablenrechnung in JavaScript
var a = 0.1+0.2+0.3;

var b = 0.3+0.3; var zero = a - b; alert(zero);

//Ergebnis: 1.1102230246251565e-16
Wir wissen aus dem vorhergehenden Abschnitt, dass die Werte in a und b rundungsbedingt nicht exakt identisch sind - sie scheinen es aber zu sein, da der Anwender nicht bemerkt, dass die Werte mit Rundungsfehlern behaftet sind. Der daraus resultierende Verlust an Genauigkeit bei der Subtraktion bedeutet hier, dass die Variable zero, die eigentlich den Wert 0 beinhalten sollte, ungleich 0 ist. Der Fehleranteil an diesem Ergebnis beträgt 100%.

Werden die vermeintlich exakten Ergebnisse, die mit einem sehr großen Prozentteil aus Rundungsfehlern bestehen, zur Weiterberechnung verwendet, potenziert sich dieser Fehler; vor allem dann, wenn die problematische Stelle in einem iterativen Algorithmus auftritt.

Information

Allgemein kann man sagen: Subtrahiert man zwei fast gleich große Zahlen, so verringert sich die Genauigkeit des Ergebnisses um so viele Stellen, wie die Ausgangszahlen von links her gemeinsam haben.


Umgehen lässt sich diese Problematik oft dadurch, dass man in den zur Berechnung verwendeten Formeln sehr vorsichtig mit Subtraktionen umgeht. Oft lässt sich eine Formel in einem Algorithmus auch so umstellen, dass die zu subtrahierenden Zahlen nicht gleich groß sind - etwa durch Anwendung binomischer Formeln. An anderen Stellen muss man, wenn Probleme auftreten und deren Ursprung bekannt sind, Zwischenergebnisse sinnvoll runden, um eine möglichst nicht-fehlerbehaftete Berechnung zu erhalten. In jedem Fall sollte man sich der Existenz des Effekts bewusst sein und dementsprechend auf die Größenordnung der zu subtrahierenden Zahlen achten, wenn man eine Subtraktion einsetzen muss.

Hinweis

Gemäß der dritten binomischen Formel lässt sich jede Subtraktion folgendermaßen umschreiben - man kann dadurch die Auslöschung deutlich einschränken, da Additionen im Gegensatz zu Subtraktionen nicht von Auslöschung betroffen sind und sich die Zahlen in der Subtraktion deutlicher voneinander unterscheiden:
a - b = (a2-b2) / (a + b)
Meine Werkzeuge
Namensräume

Varianten
Aktionen
Übersicht
Index
Mitmachen
Werkzeuge
Spenden
SELFHTML