Frage

Warum Vergleiche von NaN-Werte verhalten sich anders als alle anderen Werte? Das heißt, alle Vergleiche mit den Operatoren ==, <=,> =, <,>, wobei ein oder beiden Werten NaN false zurück, im Gegensatz zu dem Verhalten aller anderen Werte.

ich dies vereinfacht numerische Berechnungen in irgendeiner Weise annehmen, aber ich konnte einen explizit angegebenen Grund nicht finden, nicht einmal in der Lecture Notes über den Status des IEEE 754 von Kahan, die Entscheidungen im Detail andere Designs diskutiert.

Dieses abweichende Verhalten verursacht Probleme bei der einfachen Datenverarbeitung zu tun. Wenn zum Beispiel eine Liste der Datensätze Sortierung w.r.t. einig reellwertige Feld in einem C-Programm, das ich zusätzlichen Code schreiben muß NaN als maximales Element zu handhaben, da sonst der Sortieralgorithmus verwechselt werden könnte.

Edit: Die Antworten bisher alle behaupten, dass es sinnlos ist NaNs zu vergleichen.

Ich bin damit einverstanden, aber das bedeutet nicht, dass die richtige Antwort ist falsch, vielmehr wäre es a-Boolean Nicht-(NAB), die es gibt zum Glück nicht sein,.

Deshalb ist die Wahl der Rückkehr wahr oder falsch für Vergleiche in meiner Sicht willkürlich ist, und für die allgemeine Datenverarbeitung es vorteilhaft wäre, wenn es die üblichen Gesetze befolgt (Reflexivität von ==, Trichotomie von <==,>), damit Datenstrukturen, die auf diesen Gesetzen verlassen sich verwirren.

Also habe ich für einigen konkreten Vorteil bin gefragt, diese Gesetze zu brechen, nicht nur philosophische Argumentation.

Edit 2: Ich glaube, ich verstehe jetzt, warum eine schlechte Idee wäre NaN maximal zu machen, wäre es vermasselt die Berechnung der Obergrenzen.

NaN! = NaN könnte wünschenswert sein, Erfassen Konvergenz in einer Schleife zu vermeiden, wie

while (x != oldX) {
    oldX = x;
    x = better_approximation(x);
}

, die jedoch sollte besser durch den Vergleich die absolute Differenz mit einer kleinen Grenze geschrieben werden. So IMHO ist dies ein relativ schwaches Argument Reflexivität bei NaN zum Brechen.

War es hilfreich?

Lösung

war ich Mitglied des IEEE-754-Ausschusses, ich werde versuchen zu helfen, die Dinge zu klären etwas.

Zunächst einmal, Gleitkommazahlen sind nicht reelle Zahlen und Gleitkomma-Arithmetik erfüllt nicht die Axiome der reellen Arithmetik. Trichotomy ist nicht die einzige Eigenschaft der realen Arithmetik, die nicht für Schwimmer hält, ja nicht einmal der wichtigste. Zum Beispiel:

  • Addition ist nicht assoziativ.
  • Das distributive Gesetz gilt nicht.
  • Es gibt Gleitkommazahlen ohne Umkehrungen.

ich könnte weitermachen. Es ist nicht möglich, eine feste Größe arithmetischen Typ angeben, dass erfüllt alle der Eigenschaften von realen Arithmetik, dass wir kennen und lieben. Der 754 Ausschuß muss entscheiden, einige von ihnen zu verbiegen oder zu brechen. Dies wird durch ein paar ziemlich einfache Prinzipien geleitet:

  1. Wenn wir können, wir das Verhalten von realen Arithmetik entsprechen.
  2. Wenn wir nicht versuchen wir, die Verletzungen so vorhersehbar und so einfach wie möglich zu diagnostizieren.

In Bezug auf Ihren Kommentar „das bedeutet nicht, dass die richtige Antwort ist falsch“, dann ist dies falsch. Das Prädikat (y < x) fragt, ob y weniger als x. Wenn y NaN ist, dann ist es nicht weniger als jeder Gleitkommawert x, so die Antwort unbedingt falsch ist.

habe ich erwähnt, dass Trichotomie nicht gilt für Gleitkommazahlen. Allerdings gibt es eine ähnliche Eigenschaft, die halten, der Fall ist. 5.11 Klausel, Absatz 2 des 754-2008-Standard:

  

Vier gegenseitig ausschließende Beziehungen sind möglich: kleiner, gleich, größer als, und ungeordnet. Der letzte Fall tritt auf, wenn mindestens ein Operanden NaN. Jeder NaN wird mit allem, was ungeordnete vergleichen, einschließlich sich selbst.

Was das Schreiben zusätzlicher Code zu behandeln NaNs geht, ist es in der Regel möglich (wenn auch nicht immer leicht) Ihren Code so zu strukturieren, dass NaNs richtig durchfallen, aber das ist nicht immer der Fall. Wenn dies nicht der Fall, einige zusätzliche Code kann notwendig sein, aber das ist ein kleiner Preis zu zahlen für die Bequemlichkeit, die algebraische Abschluss gebracht Gleitkommaarithmetik.


Nachtrag: Viele Kommentatoren haben argumentiert, dass es sinnvoller wäre, Reflexivität der Gleichheit und Trichotomie auf dem Gelände zu erhalten, dass die Annahme NaN! = NaN scheint nicht vertraut Axiom zu bewahren. Ich bekenne, eine gewisse Sympathie für diesen Standpunkt zu haben, so dass ich dachte, ich würde diese Antwort überdenken und ein bisschen mehr Kontext zu machen.

Mein Verständnis zu Kahan aus Gesprächen ist, dass NaN = NaN entstand aus zwei pragmatischen Erwägungen:

  • Das x == y zu x - y == 0 wann immer möglich gleichwertig sein soll (über einen Satz von realer Arithmetik zu sein, macht diese Hardware-Implementierung des Vergleiches platzsparender, die zu der Zeit von größter Bedeutung war der Standard entwickelt wurde - zur Kenntnis, jedoch, dass dies für x = y = unendlich verletzt wird, so dass er sich auf seine eigene nicht ein guter Grund ist,. es vernünftigerweise gewesen gebogen (x - y == 0) or (x and y are both NaN) haben)

  • Noch wichtiger ist, gab es kein isnan( ) Prädikat zu der Zeit, dass NaN in der 8087-Arithmetik formalisiert wurde; war es notwendig, Programmierern eine bequeme und effiziente Mittel bereitzustellen, von NaN-Werte erfassen, die nicht auf Programmiersprachen abhing etwas wie isnan( ) schaffen, die viele Jahre in Anspruch nehmen. Ich werde zitieren Kahan eigene Schrift über das Thema:

  

Gab es keine Möglichkeit, NaNs loswerden, würden sie als nutzlos wie Indefinita auf Crays; sobald man festgestellt wurde, würde die Berechnung am besten gestoppt und nicht auf unbestimmte Zeit zu einem Unbestimmte Abschluss fortgesetzt. Deshalb einige Operationen auf NaNs müssen nicht NaN Ergebnisse liefern. Welche Operationen? ... Die Ausnahmen sind C Prädikate „x == x“ und „x! = X“, die jeweils 1 und 0 für esehr unendlich oder endliche Zahl x aber umkehren, wenn x keine Zahl (NaN) ist; diese stellen die einzigen einfache unexceptional Unterscheidung zwischen NaNs und Zahlen in Sprachen, die ein Wort für NaN und ein Prädikat IsNaN (x).

fehlen

Beachten Sie, dass dies auch die Logik, dass die Regeln aus so etwas wie ein „Nicht-A-Boolean“ zurück. Vielleicht war dieser Pragmatismus fehl am Platz, und der Standard sollte isnan( ) erforderlich gewesen, aber das wäre NaN fast unmöglich gemacht hat, effizient und komfortabel für mehrere Jahre zu verwenden, während der Welt für Programmiersprache Annahme wartete. Ich bin nicht überzeugt, dass ein angemessener Kompromiss gewesen wäre.

Um es deutlich zu sagen: das Ergebnis NaN == NaN ist jetzt nicht mehr ändern wird. Besser zu lernen, damit zu leben, als im Internet zu beschweren. Wenn Sie möchten, argumentieren, dass eine Ordnungsrelation für Behälter auch vorhanden ist, würde ich empfehlen dafür ein, dass Ihre Lieblings-Programmiersprache die totalOrder Prädikat in IEEE-754 (2008) standardisiert umzusetzen. Die Tatsache, dass es nicht schon spricht für die Gültigkeit von Kahan Sorge hat, dass der aktuelle Stand der Dinge motiviert.

Andere Tipps

NaN kann als eine undefinierte Zustand / Anzahl gedacht werden. ähnlich das Konzept von 0/0 undefiniert oder sqrt wird (-3) (in dem realen Zahlensystem, wo das Floating-Point-Leben).

NaN ist als eine Art Platzhalter für diesen undefinierten Zustand verwendet. Mathematisch gesehen, ist nicht definiert ungleich undefiniert. Ebenso wenig kann sagen, dass Sie ein nicht definierter Wert größer oder kleiner als ein anderer undefinierten Wert. Deshalb werden alle Vergleiche return false.

Dieses Verhalten ist auch vorteilhaft in den Fällen, in denen Sie vergleichen sqrt (-3) bis sqrt (-2). Sie würden beide Rückkehr NaN, aber sie sind nicht gleichwertig, auch wenn sie den gleichen Wert zurück. Daher Gleichheit immer false zurückgibt, wenn sie mit NaN ist das gewünschte Verhalten zu tun.

Um in noch eine weitere Analogie zu werfen. Wenn ich Ihnen zwei Box übergeben und Ihnen sage, dass keiner von ihnen einen Apfel enthält, würden Sie uns sagen, dass die Boxen die gleiche Sache enthalten?

NaN enthält keine Informationen über das, was etwas ist, genau das, was es nicht ist. Daher können diese Elemente auf jeden Fall nie gleich gesagt werden.

Aus dem Wikipedia-Artikel über NaN die folgenden Praktiken können NaNs verursachen:

  • Alle mathematischen Operationen> mit einem NaN als mindestens einen Operanden
  • Die Divisionen 0/0, ∞ / ∞, ∞ / -∞, -∞ / ∞ und -∞ / -∞
  • Die Multiplikationen 0 × ∞ und 0 × -∞
  • Die Zugänge ∞ + (-∞), (-∞) + ∞ und äquivalente Subtraktionen.
  • eine Funktion auf die Argumente außerhalb seiner Domäne Auftragen, einschließlich der Quadratwurzel einer negativen Zahl, wobei der Logarithmus einer negativen Zahl, wobei die Tangente von einem ungeraden Vielfachen von 90 Grad (oder π / 2 Radiant) oder Mitnahmen die inversen Sinus oder Kosinus einer Zahl, die kleiner ist als -1 oder mehr als +1.

Da es keine Möglichkeit gibt, die diese Operationen zu wissen, die NaN erstellt, gibt es keine Möglichkeit, sie zu vergleichen, die Sinn macht.

Ich weiß nicht, das Design Gründe, aber hier ist ein Auszug aus dem IEEE 754-1985 Standard:

"Es muss möglich sein, Gleitkommazahlen in allen unterstützten Formaten zu vergleichen, auch wenn die Operanden Formate unterscheiden sich Vergleiche sind genaue und nie Überlauf noch Unterlauf vier sich gegenseitig ausschließende Beziehungen sind möglich:.. Weniger als, gleich, größer ist als und ungeordnet. Der letzte Fall tritt auf, wenn mindestens ein Operand ist NaN. Jeder NaN mit allem, was ungeordnete vergleichen soll, einschließlich sich selbst. "

Es sieht nur eigenartig, weil die meisten Programmierumgebungen, die NaNs erlauben auch nicht zulassen, 3-wertigen Logik. Wenn Sie 3-wertigen Logik werfen in die Mischung, es wird konsequent:

  • (2.7 == 2.7) = true
  • (2.7 == 2.6) = false
  • (2.7 == NaN) = unknown
  • (NaN == NaN) = unknown

Auch ist .NET keinen bool? operator==(double v1, double v2) Betreiber bieten, so dass Sie immer noch mit dem dummen (NaN == NaN) = false Ergebnis stecken geblieben sind.

Ich vermute, dass NaN (Not A Number) bedeutet genau das: Dies ist keine Zahl und somit den Vergleich nicht wirklich Sinn machen

.

Es ist ein bisschen wie Arithmetik in SQL mit null Operanden. Sie alle Ergebnis in null

Die Vergleiche für Fließkommazahlen vergleichen numerische Werte. So können sie nicht für nicht numerische Werte verwendet werden. NaN kann daher nicht in einem numerischen Sinne verglichen werden.

Die vereinfachte Antwort ist, dass ein NaN keinen numerischen Wert hat, so gibt es nichts in ihm sonst nichts zu vergleichen.

Sie sollten erwägen den Zweck zu testen und Ihre NaNs mit + INF ersetzen, wenn Sie sie wollen INF handeln, wie +.

NaN ist eine implizite neue Instanz (von einer besonderen Art von Laufzeitfehler). Das bedeutet NaN !== NaN aus dem gleichen Grund, dass new Error !== new Error;

Und bedenken Sie solche implicitness auch außerhalb Fehler gesehen, zum Beispiel im Rahmen von regulären Ausdrücken bedeutet es /a/ !== /a/, die nur Syntax Zucker für new RegExp('a') !== new RegExp('a') ist

Während ich zustimme, dass Vergleiche von NaN mit jeder reellen Zahl ungeordnete sein sollte, denke ich, es für den Vergleich NaN mit sich selbst nur Ursache ist. Wie zum Beispiel nicht entdeckt man den Unterschied zwischen Signaling NaNs und ruhig NaNs? Wenn wir die Signale als ein Satz von Booleschen Werten denken (das heißt ein Bit-Vektor) könnte man sich fragen, ob die Bit-Vektoren die gleich oder verschieden sind, um entsprechend die Sätze. Zum Beispiel kann ein maximal vorgespannten Exponent auf Decodierung, wenn die Mantisse nach links verschoben wurden, um das höchstwertige Bit der Mantisse auf dem höchstwertigen Bit des binären Format auszurichten, würde ein negativer Wert ein ruhiger NaN und jeder positive Wert sein würde, werden, um eine Signalisierungs NaN. Null ist natürlich für die Unendlichkeit reserviert und der Vergleich würde ungeordnet sein. MSB Ausrichtung wäre für den direkten Vergleich von Signalen erlaubt sogar aus verschiedenen Binärformaten. Zwei NaNs mit dem gleichen Satz von Signalen daher entsprechen würde und geben auf Gleichheit bedeutet.

Weil Mathematik ist das Feld, wo Zahlen „nur existieren“. Bei der Berechnung müssen Sie initialize diese Zahlen und halten ihren Zustand nach Ihren Bedürfnissen. An den alten Tagen gearbeitet Speicher Initialisierung in den Möglichkeiten, wie Sie nie verlassen konnten. Sie niemals zulassen, könnte sich darüber nachdenken „oh, das mit 0xCD die ganze Zeit initialisiert werden würde, wird nicht meine algo brach“ .

So Sie die richtige brauchen nicht-Misch Lösungsmittel, das klebrig genug , um nicht nicht Ihren Algorithmus lassen in immer gesaugt und gebrochen. Gute Algorithmen Zahlen beteiligt werden meist zur Arbeit mit Beziehungen, und diejenigen, if () Beziehungen wird verzichtet.

Dies ist nur Fett, das Sie in neue Variable bei der Schöpfung setzen, statt Programmierung Zufall Hölle aus dem Computerspeicher. Und Ihr Algorithmus, was auch immer es ist, wird nicht brechen.

Als nächstes, wenn Sie noch einmal herausfinden, dass Ihr Algorithmus NaNs produziert, ist es möglich, sie zu reinigen, und sah in jeden Zweig einen nach dem anderen. Wieder „immer falsch“ Regel viel in diesen hilft.

Für mich ist der einfachste Weg, es zu erklären ist:

  

Ich habe etwas, und wenn es nicht ein Apfel, dann ist es eine Orange?

Sie können nicht NaN mit etwas anderem (auch selbst) vergleichen, weil es hat keinen Wert. Auch sie kann einen beliebigen Wert (außer eine Zahl).

  

Ich habe etwas, und wenn es dann nicht auf eine Zahl gleich ist, ist es ein String?

Sehr kurze Antwort:

Da die folgenden: nan / nan = 1 muss nicht halten. Sonst wäre inf/inf 1 sein.

(daher nan nicht gleich nan sein kann. Wie bei > oder <, wenn nan jede Ordnungsrelation in einem Satz respektieren würde die archimedische Eigenschaft erfüllen, würden wir wieder nan / nan = 1 an der Grenze).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top