Auslöschung bei Gleitkommazahlen

Im Rahmen unseres kleinen computerastronomischen Zirkulars möchte ich gern etwas über ein vernachlässigtes, aber für uns durchaus relevantes Thema berichten.

Wie die meisten sicherlich wissen, werden reelle Zahlen vom Prozessor intern als Gleitkommazahlen abgebildet. Diese besitzen einen Exponenten und eine Mantisse von gültigen Ziffern (z.B. 3.14159265358979323846E+00: hierbei ist +00 der Exponent und die 3.14... die sogenannte Mantisse in Dezimaldarstellung). Beim PC wird intern mit einer Darstellung gerechnet, die 19 bis 20 gültige Ziffern besitzt. Man könnte durchaus meinen, daß 20 Ziffern eine völlig ausreichende Genauigkeit für beinahe alle Zwecke böten und man sich diesbezüglich bei der Programmierung keine Sorgen machen müsse. Doch leider gibt es ein paar Fallstricke.

Nehmen wir einmal an, wir wollten die Zahlen

    a = 2.521738661527839093 und

    b = 0.00000000000000088935658162745108351

addieren. Beide Zahlen besitzen die für das Gleitkommaformat gültigen 20 Stellen. Bei der Addition werden jedoch die hinteren Ziffern der unteren Zahl abgeschnitten, da die Ergebnismantisse für sie keinen Platz bietet. Damit kann man zunächst noch leben, aber wenn beispielsweise a + b - a berechnet werden soll, bekommt man ein wesentlich anderes Ergebnis als  a - a + b (Verletzung des Kommutativgesetzes)!

Den Wert a von a abzuziehen wirkt nun zwar etwas konstruiert, aber es ist gut denkbar, daß mit ein paar Zwischenschritten eine solche Operation gefordert wird.

Ein anderes Beispiel: das harmlos wirkende Gleichungssystem

    ax + by = 1 und

    cx + dy = 0

kann für bestimmte Werte von a,b,c,d von der wirklichen Lösung stark abweichende Resultate für x und y liefern. Ein falsches Ergebnis kann sich beim Weiterrechnen (z.B. in einer Iteration) entsprechend fortpflanzen, vor allem, wenn damit multipliziert wird. Fatalerweise kann man sich auf das Ergebnis seiner Berechnungen trotz richtigem Formelwerk nicht verlassen! Dieses Problem wird als Auslöschung (von gültigen Ziffern) bezeichnet.Ähnliches tritt bei Brüchen auf, wenn im Nenner eine Differenz steht, z.B. bei

1  /  | x1 - x2 |

Wenn hier x1 gegen x2 geht, also beide Werte fast gleich groß sind, wird die Differenz im Nenner klein und man bekommt beim Dividieren mit sehr kleine Zahlen (es muß gar nicht mal eine Division mit 0 sein!) sehr große Ungenauigkeiten.

Wie wir gesehen haben, sind die Fälle, bei denen es zu Auslöschung kommt, nicht besonders exotisch. Grundsätzlich kann man bei der Programmierung das Problem der Auslöschung nicht lösen, sondern nur umgehen, z.B. durch Umstellen der Berechnungsreihenfolge. Nicht selten ist Auslöschung aber auch ein Indiz für eine Schwäche im Algorithmus.

Lit.: Chr. Pöppe, Rechnen mit garantierter Genauigkeit, Spektrum-Dossier Rechnerarchitekturen.