Wie verwende ich nan und inf in C?

Lesezeit: 9 Minuten

Benutzeravatar von Graphics Noob
Grafik Noob

Ich habe eine numerische Methode, die nan oder inf zurückgeben könnte, 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, Compiler-unabhängig Möglichkeit, Werte von nan und inf in C zu erstellen?

Nachdem ich ungefähr 10 Minuten lang gegoogelt hatte, konnte ich nur Compiler-abhängige Lösungen finden.

  • Floats sind im C-Standard nicht definiert. Es gibt also keine Compiler-unabhängige Möglichkeit, das zu tun, was Sie wollen.

    – Johann Kotlinski

    17. Dezember 2009 um 19:57 Uhr

Benutzeravatar von Alok Singhal
Alok Singhal

Sie können testen, ob Ihre Implementierung es hat:

#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif

Die Existenz von INFINITY wird von C99 (oder zumindest dem neuesten Entwurf) garantiert und “erweitert sich zu einem konstanten Ausdruck vom Typ Float, der positive oder vorzeichenlose Unendlichkeit darstellt, falls verfügbar; andernfalls zu einer positiven Konstante vom Typ Float, die zur Übersetzungszeit überläuft.”

NAN kann definiert werden oder nicht und “ist definiert, wenn und nur wenn die Implementierung ruhige NaNs für den Float-Typ unterstützt. Es wird zu einem konstanten Ausdruck vom Typ Float erweitert, der ein ruhiges NaN darstellt.”

Beachten Sie Folgendes, wenn Sie Gleitkommawerte vergleichen und Folgendes tun:

a = NAN;

sogar dann,

a == NAN;

ist falsch. Eine Möglichkeit, nach NaN zu suchen, wäre:

#include <math.h>
if (isnan(a)) { ... }

Sie können auch Folgendes tun: a != a testen ob a ist NaN.

Es gibt auch isfinite(), isinf(), isnormal()und signbit() Makros ein math.h im C99.

C99 hat auch nan Funktionen:

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);

(Referenz: n1256).

Dokumente INFINITY
Dokumente NAN

  • Ausgezeichnete Antwort. Referenz für die NAN- und INFINITY-Makros ist C99 §7.12 Paragraphen 4 und 5. Neben (isnan(a)) können Sie auch mit (a != a) auf einer konformen Implementierung von C nach NaN suchen.

    – Stefan Kanon

    17. Dezember 2009 um 20:29 Uhr

  • Aus Liebe zur Lesbarkeit, a != a sollte NOCH NIE verwendet werden.

    – Chris Kerekes

    20. September 2012 um 13:37 Uhr

  • @ChrisKerekes: Leider haben einige von uns NAN, aber nicht isnan(). Ja, das ist 2017. 🙁

    – eff

    1. Dezember 2017 um 12:06 Uhr

  • C erfordert nicht, wann a ist eine Nicht-Zahl, z a == NAN falsch zurückzugeben. IEEE erfordert es. Sogar Implementierungen, die sich an IEEE halten, tun dies meist. Wann isnan() nicht implementiert, immer noch besser, den Test zu verpacken als direkt zu codieren a == NAN.

    – chux – Wiedereinsetzung von Monica

    23. Juli 2020 um 16:19 Uhr


  • Um das zu ergänzen, was Chux gesagt hat, sogar auf einem IEEE 754-System mit demselben Compiler: a != a kann sich bei zwei unterschiedlichen Optimierungsstufen unterschiedlich verhalten. Verwenden Sie diesen Vergleich mit Vorsicht!

    – Will Eccles

    5. August 2021 um 19:37 Uhr

Es gibt keine Compiler-unabhängige Möglichkeit, dies zu tun, da weder die C-Standards (noch die C++-Standards) besagen, dass die Fließkomma-Mathematiktypen NAN oder INF unterstützen müssen.

Bearbeiten: Ich habe gerade den Wortlaut des C++-Standards überprüft, und er besagt, dass diese Funktionen (Mitglieder der Schablonenklasse numeric_limits):

quiet_NaN() 
signalling_NaN()

gibt NAN-Darstellungen “falls verfügbar” zurück. Es geht nicht darauf ein, was “falls verfügbar” bedeutet, sondern vermutlich so etwas wie “wenn der FP-Vertreter der Implementierung sie unterstützt”. Ebenso gibt es eine Funktion:

infinity() 

die eine positive INF-Wiedergabe “falls verfügbar” zurückgibt.

Diese sind beide in der definiert <limits> Header – 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.

  • Das ist enttäuschend und überraschend. Entsprechen C und C++ nicht den IEEE-Gleitkommazahlen, die eine Standarddarstellung für nan und inf haben?

    – Grafik-Noob

    17. Dezember 2009 um 19:05 Uhr

  • In C99 der C-Header <math.h> definiert nan(), nanf()und nanl() die unterschiedliche Darstellungen von NaN (als a double, floatund int bzw.) und Unendlich (falls verfügbar) könnte durch Generieren eines mit zurückgegeben werden log(0) oder so. Es gibt keine Standardmethode, um nach ihnen zu suchen, nicht einmal in C99. Das <float.h> Header (<limits.h> ist für ganzzahlige Typen) schweigt leider darüber inf und nan Werte.

    – Chris Lutz

    17. Dezember 2009 um 19:47 Uhr

  • Wow, das ist eine große Verwechslung. nanl() gibt a zurück long doublenicht ein int wie mein Kommentar sagt. Ich weiß nicht, warum mir das beim Schreiben nicht aufgefallen ist.

    – Chris Lutz

    17. Dezember 2009 um 19:53 Uhr

  • @Chris, siehe meine Antwort für C99.

    – Alok Singhal

    17. Dezember 2009 um 20:09 Uhr

  • @IngeHenriksen – Ziemlich sicher, dass Microsoft erklärt hat, dass es nicht die Absicht hat, VC++ C99 zu unterstützen.

    – Chris Lutz

    25. März 2013 um 3:48 Uhr

Benutzeravatar von Thorsten S
Torsten S.

Das funktioniert für beide float und double:

double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;

Bearbeiten: Wie bereits jemand sagte, sagte der alte IEEE-Standard, dass solche Werte Fallen aufwerfen sollten. Aber die neuen Compiler schalten die Traps fast immer aus und geben die angegebenen Werte zurück, weil das Trapping die Fehlerbehandlung stört.

  • Fangen war eine Möglichkeit für die Fehlerbehandlung erlaubt unter 754-1985. Das von den meisten modernen Hardware/Compilern verwendete Verhalten war ebenfalls erlaubt (und war das bevorzugte Verhalten für viele Mitglieder des Komitees). Viele Implementierer gingen fälschlicherweise davon aus, dass Trapping aufgrund der unglücklichen Verwendung des Begriffs „Ausnahmen“ im Standard erforderlich sei. Dies wurde in der überarbeiteten 754-2008 deutlich klargestellt.

    – Stefan Kanon

    17. Dezember 2009 um 22:39 Uhr

  • Hi, Stephen, du hast Recht, aber der Standard sagt auch: „Ein Benutzer sollte in der Lage sein, einen Trap für jede der fünf Ausnahmen anzufordern, indem er einen Handler dafür angibt. Er sollte in der Lage sein, anzufordern, dass ein vorhandener Handler deaktiviert wird , gespeichert oder wiederhergestellt. Er sollte auch in der Lage sein, festzustellen, ob ein bestimmter Trap-Handler für eine bestimmte Ausnahme aktiviert wurde.” „sollte“ wie definiert (2. Definitionen) bedeutet „dringend empfohlen“ und seine Implementierung sollte nur ausgelassen werden, wenn die Architektur usw. es unpraktisch macht. 80×86 unterstützt den Standard vollständig, also gibt es für C keinen Grund, ihn nicht zu unterstützen.

    – Torsten S.

    18. Dezember 2009 um 12:14 Uhr

  • Ich stimme zu, dass C 754 (2008) Gleitkommazahl erfordern sollte, aber es gibt gute Gründe dafür, dies nicht zu tun; Insbesondere wird C in allen anderen Umgebungen als x86 verwendet – einschließlich eingebetteter Geräte, die keine Hardware-Gleitkommazahlen haben, und Signalverarbeitungsgeräten, bei denen Programmierer nicht einmal Gleitkommazahlen verwenden möchten. Zu Recht oder zu Unrecht, diese Verwendungen sind für eine Menge Trägheit in der Sprachspezifikation verantwortlich.

    – Stefan Kanon

    19. Dezember 2009 um 1:05 Uhr

  • Ich weiß nicht, warum die oberste Antwort es dort oben geschafft hat. Es gibt keine Möglichkeit, die angeforderten Werte zu erzeugen. Diese Antwort tut es.

    – Trockendamm

    14. Oktober 2014 um 18:39 Uhr

  • #define is_nan(x) ((x) != (x)) kann als einfacher, tragbarer Test für NAN nützlich sein.

    – Bob Stein

    17. Januar 2019 um 18:11 Uhr

Benutzeravatar von Aaron
Aaron

Ein Compiler-unabhängiger, aber kein prozessorunabhängiger Weg, um diese zu erhalten:

int inf = 0x7F800000;
return *(float*)&inf;

int nan = 0x7F800001;
return *(float*)&nan;

Dies sollte auf jedem Prozessor funktionieren, der das IEEE 754-Gleitkommaformat verwendet (was x86 tut).

UPDATE: Getestet und aktualisiert.

double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);

  • Dies ist eine intelligente tragbare Lösung! C99 erfordert strtod und konvertiert NaNs und Infs.

    – ulidtko

    6. Januar 2015 um 10:24 Uhr

  • Nicht, dass diese Lösung einen Nachteil hätte; sie sind keine Konstanten. Sie können diese Werte beispielsweise nicht verwenden, um eine globale Variable zu initialisieren (oder um ein Array zu initialisieren).

    – Markus

    15. Januar 2016 um 9:33 Uhr


  • @ Marc. Sie können immer eine Initialisierungsfunktion haben, die diese einmal aufruft und sie im globalen Namensraum festlegt. Es ist ein sehr praktikabler Nachteil.

    – Verrückter Physiker

    2. Juli 2020 um 21:46 Uhr

Benutzeravatar von 4pie0
4pie0

<inf.h>

/* IEEE positive infinity.  */

#if __GNUC_PREREQ(3,3)
# define INFINITY   (__builtin_inff())
#else
# define INFINITY   HUGE_VALF
#endif

und

<bits/nan.h>
#ifndef _MATH_H
# error "Never use <bits/nan.h> directly; include <math.h> instead."
#endif


/* IEEE Not A Number.  */

#if __GNUC_PREREQ(3,3)

# define NAN    (__builtin_nanf (""))

#elif defined __GNUC__

# define NAN \
  (__extension__                                  \
   ((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; })  \
    { __l: 0x7fc00000UL }).__d)

#else

# include <endian.h>

# if __BYTE_ORDER == __BIG_ENDIAN
#  define __nan_bytes       { 0x7f, 0xc0, 0, 0 }
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
#  define __nan_bytes       { 0, 0, 0xc0, 0x7f }
# endif

static union { unsigned char __c[4]; float __d; } __nan_union
    __attribute_used__ = { __nan_bytes };
# define NAN    (__nan_union.__d)

#endif  /* GCC.  */

  • Dies ist eine intelligente tragbare Lösung! C99 erfordert strtod und konvertiert NaNs und Infs.

    – ulidtko

    6. Januar 2015 um 10:24 Uhr

  • Nicht, dass diese Lösung einen Nachteil hätte; sie sind keine Konstanten. Sie können diese Werte beispielsweise nicht verwenden, um eine globale Variable zu initialisieren (oder um ein Array zu initialisieren).

    – Markus

    15. Januar 2016 um 9:33 Uhr


  • @ Marc. Sie können immer eine Initialisierungsfunktion haben, die diese einmal aufruft und sie im globalen Namensraum festlegt. Es ist ein sehr praktikabler Nachteil.

    – Verrückter Physiker

    2. Juli 2020 um 21:46 Uhr

Benutzeravatar von Douglas Bagnall
Douglas Bagall

Ich benutze normalerweise

#define INFINITY (1e999)

oder

const double INFINITY = 1e999

was zumindest in IEEE 754-Kontexten funktioniert, da der höchste darstellbare Doppelwert ungefähr ist 1e308. 1e309 würde genauso gut funktionieren, wie würde 1e99999, aber drei Neunen sind ausreichend und einprägsam. Da dies entweder ein doppeltes Literal ist (in der #define Fall) oder eine tatsächliche Inf -Wert, bleibt er unendlich, auch wenn Sie 128-Bit-Floats („long double“) verwenden.

  • Das ist meiner Meinung nach sehr gefährlich. Stellen Sie sich vor, wie jemand Ihren Code in etwa 20 Jahren auf 128-Bit-Floats migriert (nachdem Ihr Code eine unglaublich komplexe Entwicklung durchlaufen hat, von der Sie heute keine der Phasen vorhersagen konnten). Plötzlich erhöht sich der Exponentenbereich drastisch, und alle Ihre 1e999 Literale runden nicht mehr auf +Infinity. Gemäß Murphys Gesetzen bricht dies einen Algorithmus. Schlimmer noch: Ein menschlicher Programmierer, der den “128-Bit”-Build durchführt, wird diesen Fehler wahrscheinlich nicht im Voraus erkennen. Dh höchstwahrscheinlich Es wird zu spät sein wenn dieser Fehler gefunden und erkannt wird. Sehr gefährlich.

    – ulidtko

    6. Januar 2015 um 10:51 Uhr

  • Natürlich ist das obige Worst-Case-Szenario alles andere als realistisch. Aber denken Sie trotzdem an die Alternativen! Es ist besser, auf der sicheren Seite zu bleiben.

    – ulidtko

    6. Januar 2015 um 10:53 Uhr

  • “In 20 Jahren”, heh. Komm schon. Diese Antwort ist es nicht das Schlecht.

    – alecov

    28. Januar 2016 um 18:50 Uhr

  • @ulidtko Das gefällt mir auch nicht, aber wirklich?

    – Iharob Al Asimi

    15. Juni 2016 um 5:30 Uhr

1421060cookie-checkWie verwende ich nan und inf in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy