Kann man einen Algorithmus programmieren, der sich selbst in Echtzeit auf Fehler prüfen kann?
Etwas in dieser Richtung habe ich vor gut 25 Jahren programmiert.
Es handelte sich um ein Messgerät, welches das Anfahren eines Kernreaktors überwacht. Dazu wird der Neutronenfluss gemessen und bei einem zu rasanten Anstieg wird dies dem Reaktorschutzsystem signalisiert. Da der Neutronenfluss im Verlauf des Anfahrens über viele Dekaden hinweg ansteigt, mussten alle Berechnungen (Filtern, Skalieren, relative Änderungsgeschwindigkeit berechnen, Grenzwerte überwachen, Logarithmieren) mittels einer zugekauften Gleitpunktarithmetik per Software durchgeführt werden. Als Prozessor wurde ein Mikrocontroller der Familie Intel 8051 eingesetzt. Dessen Festpunktarithmetik-Befehle konnten als Operanden nur einzelne Bytes verarbeiten. Glücklicherweise lag uns die zugekaufte Gleitpunktarithmetik als Assembler-Quelltext vor.
In diesem Messgerät teilten sich 3 Mikrocontroller die Arbeit, welche über einen seriellen Bus gekoppelt waren. Der I/O-Prozessor führte die eigentliche Signalverarbeitung durch. Dessen Programmumfang lag bei etwa 8 kByte. Eine der Funktionen des sogenannten Hauptprozessors war es, den I/O-Prozessor zu überwachen. Der I/O-Prozessor schickte dazu regelmäßig einen Schnappschuss seiner Daten an den Hauptprozessor, welcher seinerseits nachrechnete, ob er aus den Eingangsdaten und den Daten des internen Zustands identische Ausgangsdaten heraus bekommt.
Dies funktioniert aufgrund der Redundanz bestens, wenn man einen Ausfall der Rechner-Hardware erkennen möchte.
Was passiert aber, wenn die Software der Gleitpunkt-Arithmetik einen Fehler enthält? Dann kann ich dies nicht erkennen, da eine identische Nachrechnung den Fehler identisch reproduziert. Das ist dann der in sicherheitskritischen Systemen gefürchtete "systematische Fehler".
Dem kann man aber abhelfen durch eine "diversitäre Rückwärtsrechnung". Man rechnet aus den Ergebnisdaten rückwärts, bis man die Eingangsdaten erhält und vergleicht dann mit den tatsächlichen Eingangsdaten. Zum Beispiel wird aus der Division eine Multiplikation und aus dem Logarithmus eine Exponentialfunktion.
Dies ist aber nicht so einfach, wie es sich anhört. All diese Rechenoperationen liefern ihre Ergebnisse mit einem gewissen Fehleranteil aufgrund von Rundungsfehlern wegen der endlichen Genauigkeit der Zahldarstellung. Also muss man beim abschließenden Vergleich mit einer gewissen Diskrepanz rechnen. Wie soll man diese nun bewerten?
Ganz einfach. Man realisiert eine Intervall-Arithmetik. Für alle Eingangsoperanden ist ein Intervall definiert, in dem sie sich befinden können. Als Ergebnis einer Rechenoperation erhält man für die Ausgangsgröße ebenfalls ein Intervall, innerhalb dessen sie sich befinden muss. Dieses Rechnen mit Intervallen zieht sich nun durch den gesamten Signalfluss hindurch, erst vorwärts und dann rückwärts - bis hin zur abschließenden Bewertung.
Die vorhandene Gleitpunkt-Arithmetik wurde also zu einer Intervall-Arithmetik erweitert. Gleichzeitig mit der eigentlichen Rechnung wird das Ergebnis-Intervall berechnet, also der Bereich, in dem der wahre Wert des Ergebnisses liegt. Dazu wird die Zahldarstellung der Gleitpunktzahlen um eine Intervallangabe (delta >= 0, ebenfalls als Gleitpunktzahl) erweitert.
Um Formeln für die Berechnung der Intervalle zu erhalten, musste ich die Software des Arithmetik-Pakets analysieren, wobei man da schon vereinfachen darf. Als Ergebnis bekam ich dann zum Beispiel folgende Ausdrücke:
E := X * Y  entspricht: 
    E.wert := X.wert * Y.wert 
    E.delta := 6.0e-8*E.betrag + Y.betrag*X.delta + 
                                X.betrag*Y.delta + 
                                X.delta*Y.delta + 4.8e-38 
 E := ln(X) entspricht: 
    E.wert := ln(X.wert) 
    E.delta := 1.806e-7*E.betrag + 2.373e-7 + X.delta/X.wert 
Getestet habe ich diesen Mechanismus natürlich auch. Der beidseitige Einbau eines klitzekleinen Fehlers in eine Routine führte zuverlässig zum Ansprechen der Überwachung.