2015-05-14 3 views
12

Ich kenne die üblichen Probleme mit Fließkommaarithmetik und Genauigkeitsverlust, also ist das nicht die übliche Frage, warum 0.1 + 0.2 != 0.3 und dergleichen.Normkonforme Möglichkeit, eine Gleitkomma-Äquivalenzbeziehung zu definieren

Stattdessen möchte ich eigentlich ein binäres Prädikat in C++ (in einer 100% standardkonforme Art und Weise) zu implementieren, die tatsächlich implementiert eine echte mathematische equivalence relationship (dh reflexiv zu sein, transitiv und symmetrisch), so dass zwei Doppelzimmer sind in der gleichen Äquivalenzklasse, wenn sie in jeder Hinsicht den exakt gleichen Wert darstellen, wobei Eckfälle wie 0.0 und -0.0 unterschieden werden, aber alle NaN Werte als in der gleichen Äquivalenzklasse liegend behandelt werden. (Insbesondere ist der Standard == nicht das, was ich will, weil es im Fall von NaN nichtreflexiv ist, und nicht zwischen 0.0 und negativem -0.0 unterscheidet, die ich in verschiedenen Äquivalenzklassen sein möchte, da sie tatsächlich unterschiedlich sind Werte und führen zu unterschiedlichen Laufzeitverhalten).

Was ist der kürzeste und einfachste Weg, dies zu tun, die nicht auf Typ Punning in irgendeiner Weise oder ein implementiertes Verhalten angewiesen ist? Bisher habe ich bekam:

#include <cmath> 

bool equiv(double x, double y) 
{ 
    return (x == y && (x != 0.0 || std::signbit(x) == std::signbit(y))) || 
      (std::isnan(x) && std::isnan(y)); 
} 

Ich glaube, das die Ecke Fälle behandelt Ich kenne und früher beschrieben, aber gibt es andere Ecke Fälle, dass dieser Griff nicht, dass ich fehle? Und ist das obige binäre Prädikat garantiert, um eine Äquivalenzbeziehung nach dem C++ - Standard zu definieren, oder ist eines der Verhaltensweisen nicht spezifiziert, implementierungsdefiniert usw.?

+0

NaNs können unterschiedliche "NaN-Nutzdaten" haben, die bitweise nicht identisch sind, obwohl es Ihnen vielleicht egal ist. –

+0

@ColonThirtyTwo Ich bin mir bewusst und egal :) oder mehr, dass mir egal ist, aber eigentlich wollen sie speziell für meine Zwecke gleichwertig sein. – Trantorian

+1

@Trantorian Haben Sie stattdessen über Dezimalstellen mit Festkommazahlen nachgedacht? –

Antwort

4

Sieht gut aus.

Sie können tatsächlich Funktionsaufrufe für Plattformen, die IEEE 754 (Intel's, Power's und ARMs) implementieren, loswerden, weil die speziellen Gleitkommawerte ohne Aufrufe bestimmt werden können.

bool equiv(double x, double y) { 
    return (x == y && (x || (1/x == 1/y))) || (x != x && y != y); 
} 

Die oben nutzt die Tatsache, dass IEEE:

  • Abteilung für Nicht-Null auf Null unendlich spezielle Werte ergibt, die das Zeichen behalten. Daher 1/-0. ergibt -infinity. Infinity-Sonderwerte mit dem gleichen Vorzeichen vergleichen gleich.
  • NaNs vergleichen nicht gleich.

Die ursprüngliche Version liest sich jedoch besser für die meisten Menschen. Aus der Erfahrung des Interviews zu schließen, weiß nicht jeder Entwickler, wie spezielle Gleitkommawerte entstehen und sich verhalten.

Wenn nur NaNs eine Darstellung hätten, könnten Sie einfach memcmp tun.


Im Hinblick auf C++ und Standards C-Sprache, sagt The New C Standard Buch:

Die Gleitkomma Begriff IEEE oft zu hören ist. Diese Verwendung kam zustande, weil die ursprünglichen Standards zu diesem Thema von der IEEE veröffentlicht wurden. Dieser Standard für binäre Gleitkommaarithmetik ist das, was viele Host-Prozessoren seit über einem Jahrzehnt bieten. Seine Verwendung ist jedoch nicht von C99 vorgeschrieben.

Die in diesem Standard angegebene Darstellung für binäre Fließkommazahl wird von der Intel x86-Prozessorfamilie Sun SPARC, HP PA-RISC, IBM P OWER PC, HP-DEC-Alpha und den meisten modernen Prozessoren verwendet (Einige DSP-Prozessoren unterstützen eine Untermenge oder machen kleine Änderungen aus Kosten-/Leistungsgründen; während andere größere Unterschiede aufweisen, verwendet TMS320C3x beispielsweise Zweierkomplemente). Es gibt auch eine öffentlich verfügbare Software-Implementierung dieses Standards.

Andere Darstellungen werden weiterhin von Prozessoren unterstützt (IBM 390 und HP - war DEC - VAX) mit einem bestehenden Kundenstamm, der der Veröffentlichung der Dokumente vorausgeht, auf denen dieser Standard basiert. Diese Darstellungen werden wahrscheinlich noch einige Zeit unterstützt, da der vorhandene Code darauf verwendet (die IBM 390 und HP-DEC-Alpha unterstützen sowohl die jeweiligen älteren Repräsentationen ihrer Firmen als auch die IEC 60559-Anforderungen).

Es besteht die allgemeine Überzeugung, dass nach der Spezifikation des IEC 60559-Standards alle erforderlichen Funktionen durch entsprechende Implementierungen bereitgestellt werden. Es ist möglich, dass die Abhängigkeiten eines C-Programms von IEC 60559-Konstrukten, die zwischen den Implementierungen variieren können, nicht dokumentiert werden, weil diese allgemeine, falsche Überzeugung (die Person, die Dokumentation schreibt, nicht immer die Person ist, die mit diesem Standard vertraut ist).

Wie der C Standard spezifiziert der IEC 60559 Standard nicht vollständig das Verhalten jedes Konstrukts. Es bietet auch ein optionales Verhalten für einige Konstrukte, beispielsweise wenn der Unterlauf ausgelöst wird, und verfügt über optionale Konstrukte, die von einer Implementierung verwendet werden können oder nicht, wie zum Beispiel Doppelstandard. C99 bietet nicht immer eine Methode zum Ermitteln des Verhaltens einer Implementierung in diesen optionalen Bereichen. Zum Beispiel gibt es keine Standardmakros, die die verschiedenen Optionen für den Umgang mit dem Unterlauf beschreiben.

What Every Computer Scientist Should Know About Floating-Point Arithmetic sagt:

Sprachen und Compiler

Mehrdeutigkeit

Im Idealfall eine Sprachdefinition sollte die Semantik der Sprache genau genug, um zu beweisen, Aussagen über Programme definieren . Während dies normalerweise für den ganzzahligen Teil einer Sprache gilt, haben Sprachdefinitionen oft einen großen Graubereich, wenn es sich um Fließkommazahlen handelt. Vielleicht liegt das an der Tatsache, dass viele Sprachdesigner glauben, dass nichts über Gleitkommazahlen bewiesen werden kann, da dies einen Rundungsfehler mit sich bringt. Wenn dem so ist, haben die vorherigen Abschnitte den Irrtum in dieser Argumentation gezeigt. In diesem Abschnitt werden einige gebräuchliche Graubereiche in den Sprachdefinitionen erläutert, einschließlich Vorschlägen zum Umgang mit ihnen.

... Eine weitere Unklarheit in den meisten Sprachdefinitionen betrifft, was bei Überlauf, Unterlauf und anderen Ausnahmen passiert. Der IEEE-Standard spezifiziert genau das Verhalten von Ausnahmen, und so können Sprachen, die den Standard als ein Modell verwenden, jegliche Mehrdeutigkeit in diesem Punkt vermeiden.

... Ein weiterer grauer Bereich betrifft die Interpretation von Klammern. Aufgrund von Rundungsfehlern gelten die assoziativen Gesetze der Algebra nicht unbedingt für Fließkommazahlen ... Ob der Sprachstandard angibt, dass Klammern zu beachten sind, kann (x + y) + z eine völlig andere Antwort haben als x + (y + z), wie oben diskutiert.

.... Rundung kann ein Problem sein. Der IEEE-Standard definiert das Runden sehr genau und hängt vom aktuellen Wert der Rundungsmodi ab.Dies steht manchmal in Konflikt mit der Definition von impliziten Rundungen bei Typumwandlungen oder der expliziten Rundenfunktion in Sprachen.

Die Sprachstandards nicht möglicherweise können die Ergebnisse der Gleitkomma-Operationen angeben, da zum Beispiel kann man den Rundungsmodus zur Laufzeit std::fesetround mit ändern.

Also C und C++ - Sprachen haben keine andere Wahl, als Operationen auf Fließkommatypen direkt auf Hardwareanweisungen abzubilden und nicht zu stören, wie sie es tun. Daher kopieren die Sprachen den IEEE/IEC-Standard nicht und fordern ihn auch nicht an.

+0

Aber der C++ - Standard schreibt IEEE 754 nicht vor, also denke ich, dass es die Anforderungen des OP nicht erfüllen würde. – 5gon12eder

+2

@ 5gon12eder C++ - Standard lässt Gleitkommaangabe nicht angegeben, da IEEE nicht vollständig kopiert und verfolgt werden kann. –

+0

Ich habe dies neu gestellt, aber können Sie in der Frage ansprechen, wie viel von diesem Verhalten von welchen Standards abgedeckt wird? Definiert C++ insbesondere genug Verhalten von Gleitkommazahlen, um sicherzustellen, dass es sich um eine Äquivalenzklasse handelt, oder lässt es alle relevanten Verhaltensweisen für die Implementierung offen, um zu entscheiden, dass es keine 100% ige Standardmethode gibt, um zu garantieren, was ich will? – Trantorian

Verwandte Themen