3.1Fehlerarten¶
Bei numerischen Berechnungen spielen verschiedene Fehlerarten eine Rolle:
Rundungsfehler (Zwischenergebnisse werden auf die darstellbare Genauigkeit gerundet).
Datenfehler (die Eingabewerte entstehen aus (ungenauen) Messungen),
Verfahrensfehler (die eingesetzten Algorithmen liefern auch bei exakter Rechnung ohne Rundungsfehler nur Näherungslösungen).
Modellfehler (vereinfachte/idealisierte Darstellung der tatsächlichen physikalischen oder anderweitigen Gegebenheiten),
Dabei enthält der Datenfehler praktisch immer auch Rundungsfehler, da die Daten als Gleitkommazahlen an den Algorithmus übergeben werden müssen.
Obwohl die numerische Mathematik sich auf die (Vermeidung der) Auswirkungen von Rundungsfehlern konzentriert, spielen auch die anderen Fehlerarten und -quellen eine Rolle. Insbesondere zielt man gar nicht auf maximale Genauigkeit (was mit hohem Rechenaufwand verbunden ist), sondern nur darauf, dass die Auswirkungen von Verfahrens- und Rundungsfehlern nicht größer sind als zwangsläufige Abweichungen aus Daten- und Modellfehlern.
3.2Beispiel: Volumen der Erde¶
Wollen das Volumen der Erde aus gegebenem Radius (in Meter) mittels Kugelvolumen
berechnen.
Auftretende Fehler:
Modellfehler: Die Erde ist keine exakte Kugel, sondern ein Ellipsoid (auch nicht exakt).
Verfahrensfehler: Hier nicht vorhanden, sofern (bei exakten Daten) mit exaktem gerechnet wird.
Datenfehler: Exakte Bestimmung von scheitert schon an der Struktur der Erdoberfläche (Berge, Täler). Selbst mit sehr präziser Messtechnik wird man nur ein Intervall angeben können. Wählt man , beträgt der Datenfehler .
Rundungsfehler: und müssen für die Darstellung mittels Gleitkommazahlen gerundet werden. Die Zahlen 4 und 3 sind exakt darstellbar. Die Auswirkungen der Multiplikationen und der Division auf die Genauigkeit des Ergebnisses werden weiter unten untersucht.
Aufgrund der unvermeidlichen großen Modell- und Datenfehler gibt es keinen Grund die Berechnungen mit sehr großer Genauigkeit auszuführen. Solange die Rundungsfehler und deren Auswirkungen auf die einzelnen Rechenoperationen kleiner als die Modell- und Datenfehler bleiben, ist die Genauigkeit groß genug. Hier kann sogar mit 3.14 statt gerechnet werden (Verfahrensfehler!), da die dadurch verursachten Abweichungen höchstens im Zentimeterbereich liegen.
3.3Bewertung von Algorithmen¶
Gegeben ist ein Algorithmus, der “ein Problem löst”. Genauer: Es gibt eine Menge von möglichen Eingaben, eine Menge von möglichen Ausgaben und eine (exakte) Lösungsabbildung .
Zentrale Frage: Wie hängt der Ausgabefehler vom Eingabefehler ab?
Dabei nehmen wir an, dass es eine unbekannte exakte Eingabe gibt und eine bekannte mess- und rundungsfehlerbehaftete Eingabe . Der relative Eingabefehler ist dann
Die numerische Auswertung von erfolgt durch einen (potentiell fehlerhaften) Algorithmus , der auf die fehlerbehafteten Daten angewendet wird. Für den relativen Ausgabefehler erhalten wir somit
Ziel einer Fehleranalyse sind Abschätzungen der Form
wobei
gelten soll. Die Zahl ist also eine obere Schranke an den zu erwartenden Datenfehler. Praktisch wird mindestens so groß sein wie das Maschinenepsilon.
Die Funktion ist meistens ein Monom mit und einer (hoffentlich kleinen) Konstante . Je größer , desto unempfindlicher reagiert der untersuchte Algorithmus auf Datenfehler. In jedem Fall muss gelten, damit die Fehlerabschätzung eine sinnvolle Aussage liefert (“Wenn wir den Datenfehler kleiner machen, wird auch der Lösungsfehler kleiner”).
Zentrale Werkzeuge für die Herleitung solcher Abschätzungen sind die Kondition der Abbildung und die Stabilität des Algorithmus , welche im Folgenden eingeführt werden.
3.4Kondition¶
Einfaches Beispiel: Berechnung des Schnittpunktes zweier Geraden (IDVID 320).
Verlaufen die Geraden nahezu senkrecht zueinander, dann gute Kondition.
Verlaufen die Geraden nahezu parallel, dann schlechte Kondition.
Die Kondition hängt nicht nur von selbst, sondern auch von der konkreten Eingabe ab!
Die Kondition eines Problems bzw. der entsprechenden Abbildung kann man in Zahlen fassen. Für die konkrete Definition dieser Konditionszahl gibt es verschiedene Ansätze. Wir wählen zunächst den folgenden:
Der hier vorgestellte Konditionsbegriff führt immer zu linearen Fehlerzusammenhängen in (4). Dieser Ansatz ist in der Literatur auch als differentielle Fehleranalyse oder Störungstheorie 1. Ordnung zu finden.
Schlecht koniditionierte Probleme sind in der Praxis (leider) häufig anzutreffen, z.B. das bei der Computertomografie zu lösende mathematische Problem (siehe Veranstaltung zum wissenschaftlichen Rechnen).
3.5Beispiele zur Kondition¶
3.5.1Multiplikation¶
Betrachten
Für und erhalten wir . Der Ausgabefehler ist als höchstens so groß wie der Eingabefehler.
Für oder können wir nur absolute Fehler betrachten:
Ist z.B. und ist sehr groß, also auch sehr groß, so kann das Produkt der gestörten Eingaben erheblich vom tatsächlichen Produkt 0 abweichen. Wähle z.B. und . Dann ist das berechnete Produkt 10 statt 0. Praktisch ist dieser Fall aber selten von Interesse, da die Null exakt als Gleitkommazahl darstellbar ist. Dennoch ist an dieser Stelle Vorsicht geboten!
a = 0.1 * 0.1 - 0.01
b = 10 ** 20
print(a * b)173.4723475976807
3.5.2Division¶
Betrachten
Für erhalten wir . Der Ausgabefehler ist als höchstens so groß wie der Eingabefehler.
Für können wir nur absolute Fehler betrachten:
Die daraus zu ziehenden Schlüsse entsprechen denen bei der Multiplikation.
a = 0.1 * 0.1 - 0.01
b = 10 ** (-20)
print(a / b)173.4723475976807
3.5.3Quadratwurzel¶
Betrachten
Für erhalten wir . Der Ausgabefehler ist also kleiner als der Eingabefehler.
Für erhalten wir den absoluten Fehler
der bei stets größer ist als der Eingabefehler . Beachte hier, dass Eingabefehler zu undefiniertem Ergebnis bzw. komplexen Zahlen führen!
a = 0.01 - 0.1 * 0.1
print(a ** 0.5)(8.064844237971058e-26+1.3170890159654386e-09j)
from numpy import sqrt
a = 0.01 - 0.1 * 0.1
print(sqrt(a))nan
/tmp/ipykernel_25646/1240944823.py:4: RuntimeWarning: invalid value encountered in sqrt
print(sqrt(a))
3.5.4Addition und Subtraktion¶
Betrachten
Für und erhalten wir
Haben und gleiches Vorzeichen, dann ist . Haben und jedoch unterschiedliches Vorzeichen, so kann klein sein, obwohl weder noch klein ist. In diesem Fall ist sehr groß, die Addition als schlecht konditioniert! Diese Situation wird als Auslöschung bezeichnet.
Beispiel: Rechnen mit 5 Dezimalstellen, , . Durch Runden der Eingabewerte entsteht ein Eingabefehler der Größenordnung 10-4. Der Fehler im Ergebnis liegt jedoch bei 10-2, ist also deutlich größer (Details: IDVID 340).
Weiteres Beispiel: Berechne die Differenz , wobei statt und die auf 64-Bit-Gleitkommazahlen gerundeten Werte verwendet werden.
a = 1 + 11e-15
b = 1 + 10e-15
print(f'a = {a:.20f}')
print(f'b = {b:.20f}')a = 1.00000000000001110223
b = 1.00000000000000999201
Mit exakten Werten erhalten wir . Der Eingabefehler ist kleiner als 10-14, während der Ausgabefehler größer als 0.11 ist (IDVID 345). Somit weicht die tatsächliche Differenz um mehr als 11 Prozent vom berechneten Wert ab. Beachte hierbei: Wir haben exakt gerechnet, das Ergebnis also nicht gerundet. Ursache für den großen Fehler ist somit nicht ein konkreter Algorithmus (z.B. addiere exakt, runde dann auf 64-Bit-Gleitkommazahl), sondern das Problem selbst in Kombination mit leicht gestörten Eingabewerten. Berechnen wir die Differenz algorithmisch (also mit zusätzlichem Runden des Ergebnisses), so erhalten wir
c = a - b
print(f'a - b = {c}')
print( 'exakt = 1.0000000000000000e-15')a - b = 1.1102230246251565e-15
exakt = 1.0000000000000000e-15
Nur die Ziffer vor dem Komma ist korrekt!
print(1 + c) # Fehler in c nicht relevant
print(c * 10 ** 15) # Fehler in c relevant1.000000000000001
1.1102230246251565
3.5.5Sinus¶
Betrachten
Für , , erhalten wir
Für in der Nähe von Vielfachen von wird die Kondition also beliebig groß, während z.B. in der Nähe von sehr gut konditioniert ist.
from math import sin
def print_sin(a, b):
sina = sin(a)
sinb = sin(b)
print(sina)
print(sinb)
print(f'Eingabefehler: {abs((a - b) / a)}')
print(f'Ausgabefehler: {abs((sina - sinb) / sina)}')
print_sin(
3.141593,
3.141593123456789
)-3.464102066193935e-07
-4.6986699585547026e-07
Eingabefehler: 3.929751219718377e-08
Ausgabefehler: 0.3563890060887287
Alle Mantissenziffern des für 3.141593 aus dem fehlerbehafteten Wert 3.141593123456789 berechneten Ergebnisses sind falsch, nur der Exponent stimmt. Der relative Fehler liegt bei 34 Prozent. Die Konditionszahl ist . Beachte, dass die absoluten Fehler bei Eingabe und Ausgabe dennoch etwa gleich groß sind, das Ergebnis je nach Kontext also durchaus brauchbar sein kann.
print_sin(
1.570796,
1.570796123456789
)0.9999999999999466
0.9999999999999793
Eingabefehler: 7.8595049270588e-08
Ausgabefehler: 3.2751579226443866e-14
Hier stimmen fast alle Mantissenziffern trotz gleichem absoluten Fehler in der Eingabe wie zuvor (der relative Eingabefehler ist hier sogar doppelt so groß). Der relative Ausgabefehler liegt im Bereich 10-13, ist also im Größenordnungen kleiner als der relative Eingabefehler.
3.5.6Quadratische Gleichung¶
Betrachten das Lösen quadratischer Gleichungen , wobei wir nur die kleinere der beiden möglichen Lösungen berechnen möchten. Haben mit also
Für und (also oder ) erhalten wir
Für gilt somit , also gute Kondition. Für wächst die Kondition mit und wird für beliebig groß. Das Problem ist für große also sehr schlecht konditioniert (Details und grafische Interpretation: IDVID 350).
3.6Stabilität¶
Ein Algorithmus heißt also stabil, wenn er das tut, was man von ihm erwartet. Für die Formulierung präziserer Aussagen über den erwarteten Zusammenhang zwischen und gibt es verschiedene Ansätze. Wir gehen hier nur auf die beiden am weitesten verbreitetenen ein: Vorwärtsstabiliät und Rückwärtsstabilität.
Vorwärtsstabilität sichert also, dass der durch den verwendeten Algorithmus verursachte Fehler in der Größenordnung des auch bei exakter Rechnung nicht zu vermeidenden Fehlers liegt.
Für konkrete Algorithmen lassen sich Aussagen zur Vorwärtsstabilität oft nur schwer herleiten. Deshalb verwendet man fast immer den folgenden alternativen Stabilitätsbegriff.
Rückwärtsstabilität sichert also, dass die Ausgabe des Algorithmus der exakten Rechnung mit einer Eingabe entspricht, die im Rahmen der Größenordnung des ohnehin vorhandenen Eingabefehlers ebenfalls in Frage kommt.
Um Rückwärtsstabilität zu zeigen müssen zwei Fragen beantwortet werden:
Gibt es zu jeder Eingabe ein passendes ?
Wie groß ist der Abstand zwischen und zugehörigem höchstens?
Beweis: IDVID 360.
3.7Beispiele für Stabilitätsanalysen¶
3.7.1Addition/Subtraktion¶
Nach IEEE 754 erfolgt die Addition zweier Gleitkommazahlen nach folgendem Algorithmus:
Sind , die beiden Summanden und ist das Maschinenepsilon, so liefert der Algorithmus das Ergebnis
für ein mit .
Der einfache Algorithmus erlaubt eine Vorwärtsanalyse:
Die Kondition der Addition erfüllt (IDVID 370). Wir erhalten somit
Da der zu erwartende relative Eingabefehler praktisch immer größer als sein wird (Rundung jedes Summanden auf Gleitkommazahl), ist der untersuchte Algorithmus zur Addition als vorwärtsstabil anzusehen.
Zu Demonstrationszwecken untersuchen wir auch die Rückwärtsstabilität. Haben
mit , also . Der relative Fehler beim Ersetzen von durch ist
Da die zu erwartenden Eingabefehler größer als sein werden, ist der Algorithmus als rückwärtsstabil anzusehen.
3.7.2Lange Summen¶
Die Summe von Zahlen soll berechnet werden:
Untersuchen dazu zunächst den einfachsten Algorithmus:
Mit Maschinenepsilon und den aus den Rundungsschritten entstehenden Abweichungen wird also
berechnet. Der Algorithmus ist für große nicht rückwärtsstabil (und auch nicht vorwärtstabil). Für die Konstante in der Definition der Rückwärtsstabilität erhalten wir (IDVID 375).
Betrachten nun folgenden alternativen Algorithmus für Summen mit Summanden:
In der letzten Iteration ist nur noch eine Summe mit zwei Summanden zu berechnen, welche das Endergebnis darstellt. Bezeichnen wir die bei den Rundungsschritten entstehenden Abweichungen mit , , , so entspricht der Algorithmus folgender Formel:
Für die Konstante in der Definition der Rückwärtsstabilität erhalten wir (IDVID 380). Der Algorithmus kann also auch für große noch als rückwärtsstabil (und somit auch vorwärtsstabil) angesehen werden, da nur sehr langsam mit wächst.
3.7.3Quadratische Gleichung¶
Wir untersuchen zwei Algorithmen zur Berechnung der kleineren der beiden Lösungen der quadratischen Gleichung auf Stabilität.
3.7.3.1Direktes Auswerten der Lösungsformel¶
Vorwärts- und auch Rückwärtsanalyse sind hier recht mühsam. Mindestens die Rückwärtsanalyse ist mit unseren Mitteln aber machbar. Wählen einen anderen Weg: Betrachten jeden Schritt separat und schließen aus er Kondition der Einzelschritte auf die (Nicht-)Stabilität des Gesamtalgorithmus.
Schritt 1 ist stabil, liefert also bei fehlerfreier Eingabe einen Ausgabefehler unterhalb des Maschinenepsilons .
Schritt 2 erhält eine fehlerbehaftete Eingabe, ist aber gut Konditioniert. Die Division ohne Runden wird also wieder einen Ausgabefehler in der Größenordnung von liefern. Anschließendes Runden erhöht den relativen Fehler höchstens um den Faktor , sodass der Gesamtfehler nach Schritt 2 in der Größenordnung von bleibt.
Die Subtraktion in Schritt 3 ist schlecht konditioniert, wenn , insbesondere für aber gut konditioniert. Je nach Wert von kann der Ausgabefehler in Schritt 3 beliebig groß sein. Für wird er bei bleiben.
Schritte 4 und 5 verhalten sich analog zu Schritt 2, also keine relevante Fehlerverstärkung.
Schritt 6 ist schlecht konditioniert, wenn und ; sonst gut konditioniert. Fehlerverhalten analog zu Schritt 3.
Der Algorithmus ist also nur stabil, wenn gilt:
3.7.3.2Umweg über Satz von Vieta¶
Wollen einen Algorithmus, der für bei betragskleinem stabil ist. Der Satz von Vieta liefert für die beiden Lösungen der quadratischen Gleichung. Wir können also zunächst die größere Lösung berechnen und dann daraus die kleinere. Die ersten 5 Schritte bleiben unverändert:
Für ist Schritt 6 nun gut Konditioniert (unabhängig vom Wert von ). Auch Schritt 7 ist gut konditioniert solange das Ergebnis aus Schritt 6 nicht zu nah bei 0 liegt. Allerdings ist Schritt 6 für und nun schlecht konditioniert. Der Algorithmus ist also nur stabil, wenn gilt:
3.7.3.3Kombinierter Algorithmus¶
Um die kleinere Lösung einer quadratischen Gleichung stabil zu erhalten, oder auch um beide Lösungen zu erhalten, sollten also erst die obigen Schritte 1 bis 5 ausgeführt werden. Anschließend ist zu unterscheiden:
Wenn , dann Subtrahiere die Wurzel von .
Wenn , dann Addiere die Wurzel zu .
Anschließend kann über die Beziehung (Vieta!) die andere Lösung berechnet werden.
Dieser Algorithmus ist stabil, wenn .
Die bei auftretende Instabilität aufgrund von Auslöschungseffekten spielt praktisch kaum eine Rolle. In diesem Fall sind beide Lösungen sehr nah beieinander. Sind beide Lösungen hinreichend weit von der Null entfernt, werden diese trotzdem korrekt berechnet, da dann nur der durch Auslöschung entstandene absolute Fehler relevant ist für den relativen Fehler in den Lösungen. Und dieser ist sehr klein. Liegen jedoch beide Lösungen nah bei Null, so überträgt sich der durch Auslöschung entstandene große relative Fehler auf den relativen Fehler der Lösungen.
3.8Gesamtfehler¶
Faustregel: Gute Kondition des Problems und Stabilität des Algorithmus garantieren einen hinnehmbar kleinen Gesamtfehler. Schelchte Kondition oder fehlende Stabilität lassen keine brauchbaren Ergebnisse erwarten.
Beweis: IDVID 390.
Die Abschätzung zeigt, dass der Ausgabefehler um so kleiner wird, je kleiner der Eingabefehler ist (wenn bei beschränkt bleibt).

“Garbage In, Garbage Out” should not be taken to imply any sort of conservation law limiting the amount of garbage produced. Quelle: Randall Munroe, xkcd.com/2295