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
ergibt2) 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?
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.
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.
Sie könnten benutzerdefinierte Operatoren anstelle von benutzerdefinierten Typen wie diesem verwenden (dies vermeidet das Ersetzen von Float
in Ihrem Code)
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.
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.
Verwendung:
%Vor% Zum Überprüfen von NaN
/ infinity
hat Prelude zwei Funktionen isNaN
und isInfinite
.
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:
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:
Just NaN
vs Nothing
), um den Sie sich beim Konvertieren von / zu normalen Gleitkommazahlen kümmern müssen. 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. Tags und Links haskell floating-point ieee-754