Die verbreitete Ansicht, dass Gleitkommazahlen nicht auf Gleichheit verglichen werden können, ist ungenau. Gleitkommazahlen sind nicht anders als Ganzzahlen: Wenn Sie "a == b" auswerten, erhalten Sie true, wenn es sich um identische Zahlen handelt, und false, wenn nicht (unter der Voraussetzung, dass zwei NaNs natürlich nicht als identische Zahlen betrachtet werden).
Das eigentliche Problem ist folgendes: Wenn ich einige Berechnungen durchgeführt habe und mir nicht sicher bin, ob die beiden Zahlen, die ich vergleichen muss, genau korrekt sind, was dann? Dieses Problem ist sowohl für Gleitkommazahlen als auch für Ganzzahlen dasselbe. Wenn Sie den ganzzahligen Ausdruck "7/3*3" auswerten, wird er nicht gleich "7*3/3" sein.
Angenommen, wir fragen: "Wie vergleiche ich Ganzzahlen auf Gleichheit?" in einer solchen Situation. Es gibt keine einheitliche Antwort; was Sie tun sollten, hängt von der konkreten Situation ab, insbesondere von den Fehlern, die Sie haben, und dem, was Sie erreichen möchten.
Hier sind einige mögliche Optionen.
Wenn Sie ein "true"-Ergebnis erhalten möchten, wenn die mathematisch genauen Zahlen gleich wären, könnten Sie versuchen, die Eigenschaften der von Ihnen durchgeführten Berechnungen zu nutzen, um nachzuweisen, dass Sie die gleichen Fehler in den beiden Zahlen erhalten. Wenn dies möglich ist und Sie zwei Zahlen vergleichen, die sich aus Ausdrücken ergeben, die gleiche Zahlen ergeben würden, wenn sie genau berechnet werden, erhalten Sie durch den Vergleich "true". Ein anderer Ansatz besteht darin, dass Sie die Eigenschaften der Berechnungen analysieren und nachweisen könnten, dass der Fehler niemals einen bestimmten Betrag überschreitet, vielleicht einen absoluten Betrag oder einen Betrag relativ zu einer der Eingaben oder einer der Ausgaben. In diesem Fall können Sie fragen, ob sich die beiden berechneten Zahlen um höchstens diesen Betrag unterscheiden, und "true" zurückgeben, wenn sie innerhalb des Intervalls liegen. Wenn Sie keine Fehlergrenze nachweisen können, könnten Sie raten und auf das Beste hoffen. Eine Möglichkeit zu raten besteht darin, viele zufällige Proben auszuwerten und zu sehen, welche Art von Verteilung Sie in den Ergebnissen erhalten.
Natürlich haben wir mit der Anforderung, dass Sie "true" erhalten, wenn die mathematisch genauen Ergebnisse gleich sind, die Möglichkeit offen gelassen, dass Sie "true" erhalten, selbst wenn sie ungleich sind. (Tatsächlich können wir die Anforderung erfüllen, indem wir immer "true" zurückgeben. Dies macht die Berechnung einfach, ist jedoch im Allgemeinen unerwünscht, daher werde ich unten weitere Verbesserungen diskutieren.)
Wenn Sie ein "false"-Ergebnis erhalten möchten, wenn die mathematisch genauen Zahlen ungleich wären, müssen Sie nachweisen, dass Ihre Bewertung der Zahlen unterschiedliche Zahlen ergibt, wenn die mathematisch genauen Zahlen ungleich wären. Dies kann für praktische Zwecke in vielen üblichen Situationen unmöglich sein. Überlegen wir uns also eine Alternative.
Eine nützliche Anforderung könnte sein, dass wir ein "false"-Ergebnis erhalten, wenn die mathematisch genauen Zahlen um mehr als einen bestimmten Betrag voneinander abweichen. Beispielsweise möchten wir berechnen, wo ein Ball, der in einem Computerspiel geworfen wird, hingeflogen ist, und wir möchten wissen, ob er einen Schläger getroffen hat. In diesem Fall möchten wir sicherlich "true" erhalten, wenn der Ball den Schläger trifft, und wir möchten "false" erhalten, wenn der Ball weit vom Schläger entfernt ist, und wir können eine falsche "true"-Antwort akzeptieren, wenn der Ball in einer mathematisch exakten Simulation den Schläger verfehlt, aber einen Millimeter davon entfernt ist, den Schläger zu treffen. In diesem Fall müssen wir nachweisen (oder raten/schätzen), dass unsere Berechnung der Position des Balls und der Position des Schlägers einen kombinierten Fehler von höchstens einem Millimeter (für alle interessanten Positionen) haben. Dies würde es uns ermöglichen, immer "false" zurückzugeben, wenn der Ball und der Schläger mehr als einen Millimeter voneinander entfernt sind, "true" zurückzugeben, wenn sie sich berühren, und "true" zurückzugeben, wenn sie nah genug beieinander sind, um akzeptabel zu sein.
Wie also entscheiden Sie, was Sie zurückgeben, wenn Sie Gleitkommazahlen vergleichen, hängt sehr stark von Ihrer spezifischen Situation ab.
Was die Feststellung von Fehlergrenzen für Berechnungen betrifft, so kann dies ein kompliziertes Thema sein. Jede Gleitkommazahl-Implementierung, die den IEEE-754-Standard im Rundungsmodus zum nächsten Wert verwendet, gibt die Gleitkommazahl zurück, die dem exakten Ergebnis am nächsten ist, für jede Grundoperation (insbesondere Multiplikation, Division, Addition, Subtraktion, Quadratwurzel). (Im Falle eines Gleichstands wird so gerundet, dass das niederwertige Bit gerade ist.) (Seien Sie besonders vorsichtig bei Quadratwurzeln und Divisionen; Ihre Sprachimplementierung könnte Methoden verwenden, die sich bei diesen nicht an IEEE 754 halten.) Aufgrund dieser Anforderung wissen wir, dass der Fehler in einem einzelnen Ergebnis höchstens 1/2 des Werts des niederwertigsten Bits beträgt. (Wenn es mehr wäre, wäre das Runden zu einer anderen Zahl gegangen, die innerhalb des 1/2 des Werts liegt.)
Von dort aus wird es deutlich komplizierter; der nächste Schritt besteht darin, eine Operation auszuführen, bei der eine der Eingaben bereits einen Fehler aufweist. Für einfache Ausdrücke können diese Fehler durch die Berechnungen verfolgt werden, um eine Begrenzung des endgültigen Fehlers zu erreichen. In der Praxis wird dies nur in einigen Situationen durchgeführt, wie zum Beispiel bei der Arbeit an einer hochwertigen Mathematik-Bibliothek. Und natürlich benötigen Sie eine genaue Kontrolle darüber, welche Operationen durchgeführt werden. Hochsprachen geben dem Compiler oft viel Freiraum, sodass Sie möglicherweise nicht wissen, in welcher Reihenfolge die Operationen ausgeführt werden.
Zu diesem Thema könnte (und wird) noch viel mehr geschrieben werden, aber ich muss hier aufhören. Zusammenfassend lässt sich sagen: Es gibt keine Bibliotheksroutine für diesen Vergleich, da es keine einzige Lösung gibt, die den meisten Anforderungen entspricht und es sich lohnt, in eine Bibliotheksroutine aufgenommen zu werden. (Wenn das Vergleichen mit einem relativen oder absoluten Fehlerintervall für Sie ausreicht, können Sie dies einfach ohne eine Bibliotheksroutine tun.)
0 Stimmen
@tolomea: Da es von Ihrer Anwendung, Ihren Daten und Ihrem Problem abhängt - und es sich nur um eine Zeile Code handelt -, warum sollte es eine "Standardbibliotheksfunktion" geben?
14 Stimmen
@S.Lott:
all
,any
,max
,min
sind im Grunde genommen Einzeiler, und sie werden nicht nur in einer Bibliothek bereitgestellt, sondern sind eingebaute Funktionen. Die Gründe des BDFL sind also nicht das. Die eine Zeile Code, die die meisten Menschen schreiben, ist ziemlich einfallslos und funktioniert oft nicht, was ein starkes Argument dafür ist, etwas Besseres bereitzustellen. Natürlich müsste ein Modul, das andere Strategien bietet, auch Warnhinweise bereitstellen, wann sie angemessen sind und vor allem wann nicht. Numerische Analyse ist schwierig, es ist kein großes Unglück, dass Sprachdesigner normalerweise keine Tools zur Unterstützung dabei entwickeln.0 Stimmen
@Steve Jessop. Diese sammlungsbasierten Funktionen haben nicht die Anwendungs-, Daten- und Problemdomänenabhängigkeiten wie Gleitkommazahlen. Daher ist der "Einzeiler" offensichtlich nicht so wichtig wie die eigentlichen Gründe. Die numerische Analyse ist schwierig und kann kein integraler Bestandteil einer Library einer allgemeinen Zwecksprache sein.
7 Stimmen
@S.Lott: Ich würde wahrscheinlich zustimmen, wenn die Standard-Python-Distribution nicht mit mehreren Modulen für XML-Schnittstellen geliefert würde. Offensichtlich ist die Tatsache, dass verschiedene Anwendungen etwas unterschiedlich machen müssen, überhaupt kein Hindernis dafür, Module in den Basissatz aufzunehmen, um es auf die eine oder andere Weise zu tun. Sicherlich gibt es Tricks zum Vergleichen von Gleitkommazahlen, die häufig wiederverwendet werden, wobei der grundlegendste eine bestimmte Anzahl von ulps ist. Also stimme ich nur teilweise zu - das Problem ist, dass numerische Analyse schwierig ist. Python könnte grundsätzlich Werkzeuge bereitstellen, um es etwas einfacher zu machen, zumindest manchmal. Ich denke, niemand hat sich bisher freiwillig gemeldet.
0 Stimmen
@Steve Jessop. Es hängt zu sehr von Ihrer Anwendung und Ihren Daten und Ihrem Problemfeld ab. Da es letztlich auf eine schwer zu gestaltende Codezeile hinausläuft, fügen die Bibliotheken nicht viel hinzu. Ein Buch wie Numerical Recipes in Python wäre hilfreicher als eine Bibliothek, die schwierige Probleme banalisiert.
0 Stimmen
@S.Lott: Also, ich denke, die Frage ist, ob der Code in diesem Buch tatsächlich nützlich ist. Wenn ja, gibt es keinen speziellen Grund, warum es nicht eine Bibliothek sein könnte, obwohl zugegebenermaßen Personen, die das Buch nicht gelesen haben, Schwierigkeiten haben könnten, es korrekt zu verwenden. Auf der anderen Seite können Personen, die ein Buch über Unicode nicht gelesen haben,
str
leicht falsch verwenden. Wenn Sie erst einmal eine Bibliothek mit wertvollen Tools haben, könnte beurteilt werden, ob sie zu den üblichen Kriterien gehört. Der Unterschied zwischen beispielsweise Textverarbeitung (sehr anwendungs- und datenspezifisch) und numerischer Verarbeitung besteht darin, wie viele Personen diese benötigen.4 Stimmen
Ebenfalls heißt es "es läuft auf eine schwer zu gestaltende Codezeile hinaus" - wenn es immer noch ein Einzeiler ist, wenn du es richtig machst, denke ich, dass dein Monitor breiter ist als meiner ;-). Wie dem auch sei, ich halte das gesamte Gebiet für ziemlich spezialisiert, im Sinne, dass die meisten Programmierer (einschließlich mir) es sehr selten verwenden. In Verbindung mit der Schwierigkeit wird es also nicht ganz oben auf der "meistgesuchten" Liste für Kernbibliotheken in den meisten Sprachen stehen.
0 Stimmen
@S.Lott Bisher scheinen wir nur zwei praktikable Lösungen zu haben, von denen eine nur gültig ist, wenn Sie die Größenordnung der Eingaben kennen. Sicher müssen die Epsilon-Werte je nach Anwendung angepasst werden, aber sie sind Argumente.
0 Stimmen
Vielleicht möchten Sie Ihren Link aktualisieren, randomascii.wordpress.com/2012/02/25/…
0 Stimmen
Nie hatte solche Probleme mit Matlab, warum?
0 Stimmen
@bonobo Vielleicht gibst du nicht genug Mühe stackoverflow.com/questions/23824577/…