Ich habe eine numerische Methode, die nan oder inf zurückgeben kann, wenn ein Fehler aufgetreten ist, und zu Testzwecken möchte ich sie vorübergehend zwingen, nan oder inf zurückzugeben, um sicherzustellen, dass die Situation korrekt behandelt wird. Gibt es eine zuverlässige, compilerunabhängige Möglichkeit, Werte für nan und inf in C zu erstellen?
Nachdem ich ungefähr 10 Minuten gegoogelt habe, konnte ich nur compilerabhängige Lösungen finden.
Antworten:
Sie können testen, ob Ihre Implementierung es hat:
Die Existenz von
INFINITY
wird durch C99 (oder zumindest den neuesten Entwurf) garantiert und "erweitert sich zu einem konstanten Ausdruck des Typs float, der eine positive oder vorzeichenlose Unendlichkeit darstellt, falls verfügbar; andernfalls zu einer positiven Konstante des Typs float, die zur Übersetzungszeit überläuft."NAN
kann definiert werden oder nicht, und "wird genau dann definiert, wenn die Implementierung leise NaNs für den Float-Typ unterstützt. Sie wird zu einem konstanten Ausdruck des Typs float erweitert, der ein leises NaN darstellt."Beachten Sie Folgendes, wenn Sie Gleitkommawerte vergleichen, und gehen Sie wie folgt vor:
sogar dann,
ist falsch. Eine Möglichkeit, nach NaN zu suchen, wäre:
Sie können auch Folgendes tun: um
a != a
zu testen, oba
NaN vorhanden ist.Es gibt auch
isfinite()
,isinf()
,isnormal()
, undsignbit()
Makros inmath.h
in C99.C99 hat auch
nan
Funktionen:(Referenz: n1256).
Docs INFINITY Docs NAN
quelle
a != a
sollte NIEMALS verwendet werden.a
es sich um eine Nicht-Zahl handelt, uma == NAN
false zurückzugeben. IEEE erfordert es. Sogar Implementierungen, die IEEE entsprechen, tun dies meistens . Wennisnan()
nicht implementiert, ist es immer noch besser, den Test zu verpacken als direkt zu codierena == NAN
.Es gibt keine vom Compiler unabhängige Methode, da weder die C- (noch die C ++) Standards besagen, dass die Gleitkomma-Mathe-Typen NAN oder INF unterstützen müssen.
Bearbeiten: Ich habe gerade den Wortlaut des C ++ - Standards überprüft und es heißt, dass diese Funktionen (Mitglieder der Vorlagenklasse numeric_limits):
Wir werden NAN-Darstellungen "falls verfügbar" zurückgeben. Es wird nicht erweitert, was "falls verfügbar" bedeutet, sondern vermutlich "wenn der FP-Vertreter der Implementierung sie unterstützt". Ebenso gibt es eine Funktion:
Dies gibt einen positiven INF-Repräsentanten "falls verfügbar" zurück.
Diese sind beide in der
<limits>
Kopfzeile definiert - ich würde vermuten, dass der C-Standard etwas Ähnliches hat (wahrscheinlich auch "falls verfügbar"), aber ich habe keine Kopie des aktuellen C99-Standards.quelle
<math.h>
definiertnan()
,nanf()
undnanl()
dass die Rückkehr verschiedener Darstellungen von NaN (als adouble
,float
undint
jeweils) und unendlich (wenn vorhanden) durch die Erzeugung eines mit zurückgeführt werden könntelog(0)
oder so. Selbst in C99 gibt es keine Standardmethode, um nach ihnen zu suchen. Der<float.h>
Header (<limits.h>
ist für integrale Typen) enthält leider keine Informationeninf
undnan
Werte.nanl()
gibt ein zurücklong double
, nichtint
wie mein Kommentar sagt. Ich weiß nicht, warum ich das nicht bemerkt habe, als ich es getippt habe.Dies funktioniert für beide
float
unddouble
:Bearbeiten: Wie jemand bereits sagte, sagte der alte IEEE-Standard, dass solche Werte Fallen auslösen sollten. Die neuen Compiler schalten jedoch fast immer die Traps aus und geben die angegebenen Werte zurück, da das Trapping die Fehlerbehandlung beeinträchtigt.
quelle
#define is_nan(x) ((x) != (x))
kann als einfacher, tragbarer Test für NAN nützlich sein.Ein compilerunabhängiger Weg, aber kein prozessorunabhängiger Weg, um diese zu erhalten:
Dies sollte auf jedem Prozessor funktionieren, der das Gleitkommaformat IEEE 754 verwendet (was x86 tut).
UPDATE: Getestet und aktualisiert.
quelle
(float &)
? Das sieht für mich nicht nach C aus. Sie brauchenint i = 0x7F800000; return *(float *)&i;
0x7f800001
dies im IEEE-754-Standard ein sogenanntes Signalisierungs- NaN ist. Obwohl die meisten Bibliotheken und Hardware keine Signalisierung von NaNs unterstützen, ist es wahrscheinlich besser, ein leises NaN wie zurückzugeben0x7fc00000
.quelle
strtod
und konvertiert NaNs und Infs.und
quelle
Ich bin auch überrascht, dass dies keine Kompilierungszeitkonstanten sind. Aber ich nehme an, Sie könnten diese Werte leicht genug erstellen, indem Sie einfach eine Anweisung ausführen, die ein solches ungültiges Ergebnis zurückgibt. Teilen durch 0, log von 0, tan von 90, so etwas.
quelle
Ich benutze normalerweise
oder
Dies funktioniert zumindest in IEEE 754-Kontexten, da der höchste darstellbare Doppelwert ungefähr ist
1e308
.1e309
würde genauso gut funktionieren wie würde1e99999
, aber drei Neunen sind ausreichend und unvergesslich. Da dies entweder ein Doppelliteral (im#define
Fall) oder ein tatsächlicherInf
Wert ist, bleibt es unendlich, selbst wenn Sie 128-Bit-Floats („Long Double“) verwenden.quelle
1e999
Literale runden nicht mehr auf+Infinity
. Nach Murphys Gesetzen bricht dies einen Algorithmus. Schlimmer noch: Ein menschlicher Programmierer, der den "128-Bit" -Bau ausführt, wird diesen Fehler wahrscheinlich nicht im Voraus erkennen. Das heißt, es wird höchstwahrscheinlich zu spät sein, wenn dieser Fehler gefunden und erkannt wird. Sehr gefährlich.Hier ist eine einfache Möglichkeit, diese Konstanten zu definieren, und ich bin mir ziemlich sicher, dass sie portabel sind:
Wenn ich diesen Code ausführe:
Ich bekomme:
quelle