IEEE-Gleitkomma-Signalisierung NaN (sNaN) in Haskell

8

Gibt es eine Möglichkeit, Signalisierungs-NaN in Haskell zu definieren? Ich habe zwei Ansätze gefunden, um mit NaNs umzugehen:

1) benutze 0/0, was ziemlich nan

ergibt

2) Paket Data.Number.Transfinite , das hat auch keine signalisierenden NaNs.

PS Gibt es eine Möglichkeit, Word64 Bit für Bit in Double ohne C-Bibliothek zu schreiben?

    
Aleksandr Pakhomov 24.01.2014, 23:07
quelle

5 Antworten

2

Ich habe einen nicht portablen Weg gefunden:

%Vor%

was vollkommen fehlschlägt. Es stellte sich heraus, dass FPU-Ausnahmen für Haskell eine schlechte Idee sind. Sie sind standardmäßig aus einem guten Grund deaktiviert. Sie sind in Ordnung, wenn Sie C / C ++ / etwas anderes in gdb debuggen. Ich möchte keine Haskell-Core-Dumps debuggen, da sie nicht zwingend erforderlich sind. Die Aktivierung von FE_INVALID exceptions verursacht 0/0 und fügt zu NaNs in Data.Number.Transfinite und GHC.Real zum Absturz hinzu. Aber 0/0 berechnet vor enableexcept erzeugt keine Ausnahmen zusätzlich.

Ich werde einige einfache Fehler in meiner Aufgabe verwenden. Ich brauche sNaN an nur einer Stelle.

    
Aleksandr Pakhomov 25.01.2014, 01:37
quelle
2

Wie wäre es mit Data.Maybe ?

Sie würden Maybe Float als Datentyp verwenden (vorausgesetzt, Sie möchten Float verwenden) und Just x für den Nicht-NaN-Wert x , während Nothing für NaN steht.

Sie müssten jedoch mindestens eine Num -Instanz raddieren, um mit Maybe Float anstelle von Float rechnen zu können. Sie können fromJust als Dienstprogrammfunktion dafür verwenden.

Ob dies als qNaN oder sNaN ausgedrückt wird, hängt vollständig von Ihrer Implementierung ab.

    
Uli Köhler 24.01.2014 23:33
quelle
0

Sie könnten benutzerdefinierte Operatoren anstelle von benutzerdefinierten Typen wie diesem verwenden (dies vermeidet das Ersetzen von Float in Ihrem Code)

%Vor%

Der zweite print löst den Fehler aus.

Hinweis: Ich bin nicht sicher, ob es eine bessere Möglichkeit gibt, dies zu formatieren, und Sie sollten wahrscheinlich keine konkreten Typen in der Funktionssignatur verwenden.

    
Uli Köhler 25.01.2014 00:39
quelle
0

Sie können Data.Ratio verwenden, um Nan / Infinity zu erstellen unter Verwendung der Verhältnisse 1/0 (unendlich) oder 0/0 (NaN).

Ein schnellerer, aber weniger portabler Ansatz ist die Verwendung von GHC.Real , die infinity und notANumber exportiert.

%Vor%

Verwendung:

%Vor%

Zum Überprüfen von NaN / infinity hat Prelude zwei Funktionen isNaN und isInfinite .

    
kvanberendonck 25.01.2014 00:47
quelle
0

Sie können so etwas tun:

%Vor%

Sie würden natürlich mehr Typklassen benötigen, um das volle Float -Erlebnis zu erhalten, aber wie Sie sehen können, ist es ziemlich einfach, wenn die liftSNaN* -Funktionen definiert sind. Der SNaN -Konstruktor wandelt einen Wert in einem beliebigen RealFloat -Typ in einen, der explodiert, wenn es ein NaN ist, und Sie verwenden es in einem beliebigen Vorgang (einige von diesen möchten Sie vielleicht mit NaNs arbeiten, vielleicht == und / oder show ; Sie können nach Geschmack variieren). unSNaN macht SNaN wieder zu einem stillen NaN-Typ.

Es verwendet immer noch nicht direkt den Typ Float (oder Double oder was auch immer), aber wenn Sie nur Ihre Typ-Signaturen ändern, wird alles funktionieren; Die Num und Show Instanzen, die ich angegeben habe, bedeuten, dass numerische Literale ebenso einfach als SNaN Float akzeptiert werden, da sie Float sind, und sie show auch gleich sind. Wenn Sie es satt haben, SNaN in die Typ-Signaturen einzutippen, könnten Sie leicht type Float' = SNaN Float oder sogar:

%Vor%

Obwohl ich wette, dass das irgendwann für jemanden Verwirrung stiften würde! Aber damit sollte genau der gleiche Quellcode kompiliert und funktionieren, vorausgesetzt, Sie haben alle benötigten Typenklassen ausgefüllt und Sie rufen keinen anderen Code auf, den Sie nicht ändern können jeder Typ in einer geeigneten Typklasse).

Dies ist im Grunde eine Ausarbeitung von Uli Köhlers erstem Vorschlag, eine Num -Instanz für Maybe Float bereitzustellen. Ich habe gerade NaNs direkt verwendet, um NaNs darzustellen, anstatt Nothing , und isNan verwendet, um sie anstelle der Fallanalyse für Maybe (oder isJust ) zu erkennen.

Die Vorteile eines newtype-Wrappers gegenüber Maybe sind:

  1. Sie vermeiden die Einführung eines anderen "ungültigen" Wertes für die Ausführung ( Just NaN vs Nothing ), um den Sie sich beim Konvertieren von / zu normalen Gleitkommazahlen kümmern müssen.
  2. Neue Typen werden in GHC deaktiviert. Ein SNaN Float wird zur Laufzeit identisch mit dem entsprechenden Float dargestellt. Es gibt also keinen zusätzlichen Speicherplatz für die Zelle Just , und die Konvertierung zwischen SNaN Float und Float ist ein freier Vorgang. SNaN ist nur ein Tag, das bestimmt, ob implizite Checks "wenn NaN dann explodieren" möchten, die in Ihre Operationen eingefügt werden.
Ben 25.01.2014 01:04
quelle