2008-11-30 14 views
14

Bisher habe ich viele Beiträge gesehen, die sich mit der Gleichheit von Fließkommazahlen beschäftigen. Die Standardantwort auf eine Frage wie "Wie sollten wir entscheiden, ob x und y gleich sind?"Sollten wir Gleitkommazahlen für Gleichheit mit einem * relativen * Fehler vergleichen?

ist
abs(x - y) < epsilon 

wobei Epsilon ist ein fixiert, kleine Konstante. Dies liegt daran, dass die "Operanden" x und y oft die Ergebnisse einiger Berechnungen sind, bei denen ein Rundungsfehler vorliegt, daher ist der Standard-Gleichheitsoperator == nicht was wir meinen, und was wir wirklich fragen sollten ist, ob x und y sind schließen, nicht gleich.

Nun, ich denke, wenn x „fast gleich“ y ist, dann ist auch x * 10^20 sollte * 10^20, in dem Sinne, y „fast gleich“ sein, dass die relativ Fehler sein sollten das gleiche (aber "relativ" zu was?). Aber mit diesen großen Zahlen würde der obige Test fehlschlagen, d. H. Diese Lösung "skaliert" nicht.

Wie würden Sie mit diesem Problem umgehen? Sollten wir die Zahlen neu skalieren oder Epsilon neu skalieren? Wie? (Oder ist meine Intuition falsch?)

ist hier ein related question, aber ich weiß nicht seine akzeptierte Antwort mag, für die reinterpret_cast Sache ein bisschen schwierig zu mir scheint, ich verstehe nicht, was los ist. Bitte versuchen Sie es mit einem einfachen Test.

Antwort

17

Es hängt alles von der spezifischen Problemdomäne ab. Ja, die Verwendung eines relativen Fehlers wird im allgemeinen Fall korrekter sein, aber es kann wesentlich weniger effizient sein, da es eine zusätzliche Gleitkommadivision beinhaltet. Wenn Sie die ungefähre Skalierung der Zahlen in Ihrem Problem kennen, ist die Verwendung eines absoluten Fehlers akzeptabel.

This page beschreibt eine Reihe von Techniken zum Vergleichen von Floats. Es geht auch über eine Reihe wichtiger Themen, wie solche mit Unternormalen, Unendlichkeiten und NaNs. Es ist eine großartige Lektüre, ich empfehle es, es durch den ganzen Weg zu lesen.

+0

Vielen Dank. Das Papier erklärt auch die Motivationen hinter der unhöflichen Besetzung zu int (obwohl ich im normalen Code würde ich für Verständlichkeit entscheiden und eine der All-Float-Lösungen verwenden :) –

+1

Aktualisierte Version des obigen Links ist [Vergleichen von Gleitkommazahlen, Ausgabe 2012] (http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) – sfstewman

1

Das Problem ist, dass mit sehr großen Zahlen, im Vergleich zu Epsilon wird fehlschlagen.

Vielleicht eine bessere (aber langsamer) Lösung wäre die Verwendung Division Beispiel:

div(max(a, b), min(a, b)) < eps + 1 

Nun ist die ‚Fehler‘ im Verhältnis wird.

+0

Genau, es ist relativ zu dem Minimum zwischen a und b, nicht wahr? –

+2

Hmmm. Vorsicht vor Spaltungen durch Null :) –

+0

Und achten Sie auf ihr Zeichen. Das Papier in Adams Antwort schlägt den relativen absoluten absoluten Vergleich vor. –

3

Als eine alternative Lösung, warum nicht nur runden oder trunkieren Sie die Zahlen und dann einen direkten Vergleich? Indem Sie die Anzahl der signifikanten Stellen im Voraus festlegen, können Sie sich der Genauigkeit innerhalb dieser Grenze sicher sein.

+0

Rundung und Kürzung funktionieren schlecht. Wenn wir auf drei Stellen runden (auf den nächsten), dann werden 1,499999999999 und 1,5000000000001 ad anders vergleichen, obwohl sie lächerlich nahe sind. Wenn wir es abschneiden, dann werden 1.999999999999 und 2.00000000000001 als unterschiedlich vergleichen, obwohl sie extrem nah sind. Jedes Rundungs- oder Trunkierungsschema weist solche Höcker auf. Jede Lösung muss mit der Subtraktion der Zahlen beginnen und dann entscheiden, ob der Unterschied groß genug ist, um signifikant zu sein. –

+1

@BruceDawson 1.4999999999999 und 1.500000000000001 auf 3 Ziffern gerundet werden als gleich ... vergleichen (beide 1,5) – colmde

+1

Huh. Ich bin nicht sicher, warum ich diese Zahlen als Beispiele gegeben habe, weil Sie Recht haben, sie arbeiten nicht, wie ich behauptete. Das eigentliche Problem ist, dass Sie zwei beliebig nahe Zahlen haben können, die voneinander abrunden und daher als unterschiedlich vergleichen, wenn sie als gleich vergleichen sollen. Für die nächste Runde: 1.50500000000000001 1.50499999999999999 Wenn sie auf drei Stellen gerundet sind, ergeben sie 1,51 und 1,50, obwohl sie von weniger als einem Teil in einer Milliarde getrennt sind. Jedes Rundungsschema wird dieses Problem mit Zahlen nahe der Spitze treffen. Deshalb ist Round-and-Compare gebrochen. –

0

Die Verwendung eines relativen Fehlers ist mindestens nicht so schlimm wie die Verwendung absoluter Fehler, aber es hat aufgrund von Rundungsproblemen subtile Probleme für Werte nahe Null. Ein bei weitem nicht perfekt, aber etwas robuster Algorithmus kombiniert absolute und relative Fehler Ansätze:

boolean approxEqual(float a, float b, float absEps, float relEps) { 
    // Absolute error check needed when comparing numbers near zero. 
    float diff = abs(a - b); 
    if (diff <= absEps) { 
     return true; 
    } 

    // Symmetric relative error check without division. 
    return (diff <= relEps * max(abs(a), abs(b))); 
} 

ich diesen Code von Bruce Dawson ausgezeichneten Artikel angepasst Comparing Floating Point Numbers, 2012 Edition, ein Lese erforderlich für alle Floating-Point-Vergleiche zu tun - ein erstaunlich komplexes Thema mit vielen Fallstricken.

0

Meistens, wenn Code Werte vergleicht, wird eine Frage beantwortet.Zum Beispiel:

  1. Wenn ich weiß, was für eine Funktion, wenn ein Wert von X gegeben zurückgegeben, kann ich davon ausgehen, es wird die gleiche Sache zurück, wenn Y gegeben?

  2. Wenn ich eine Methode habe, eine Funktion zu berechnen, die langsam aber genau ist, bin ich bereit, einige Ungenauigkeit im Austausch für die Geschwindigkeit zu akzeptieren, und ich möchte eine Kandidatenfunktion testen, die zur Rechnung passt, sind die Ausgaben von dieser Funktion nah genug an die bekannt-genaue als "richtig" zu betrachten.

die erste Frage zu beantworten, Code idealerweise einen bitweise Vergleich zu dem Wert tun soll, obwohl es sei denn, eine Sprache, die neuen Betreiber zu IEEE-754 im Jahr 2009 hinzugefügt unterstützt, das weniger als ideal effizient sein kann. Um die zweite Frage zu beantworten, sollte man definieren, welcher Grad an Genauigkeit erforderlich ist, und dagegen testen.

Ich denke nicht, dass es viel Verdienst in einer allgemeinen Methode gibt, die gleichwertige Dinge betrachtet, da unterschiedliche Anwendungen unterschiedliche Anforderungen an absolute und relative Toleranz haben werden, basierend auf den genauen Fragen der Tests Antworten.