Frage Wie benutzt man Nan und Inf in C?


Ich habe eine numerische Methode, die nan oder inf zurückgeben könnte, wenn es einen Fehler gab, und zu Testzwecken möchte ich sie vorübergehend zwingen, nan oder inf zurückzugeben, um sicherzustellen, dass die Situation korrekt gehandhabt wird. Gibt es eine zuverlässige, Compiler-unabhängig Möglichkeit, Werte von Nan und Inf in C zu erstellen?

Nach dem Googeln für ca. 10 Minuten konnte ich nur Compiler-abhängige Lösungen finden.


76
2017-12-17 18:57


Ursprung


Antworten:


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 letzten Entwurf) garantiert und "expandiert zu einem konstanten Ausdruck vom Typ float, der positiv oder vorzeichenlos ist Unendlichkeit, falls verfügbar; sonst zu einer positiven Konstante vom Typ float, die zur Übersetzungszeit überläuft. "

NAN kann oder darf nicht definiert sein und "ist genau dann definiert, wenn die Implementierung stille NaNs für den Gleitkommatyp unterstützt. Es wird zu einem konstanten Ausdruck vom Typ float erweitert, der ein ruhiges NaN darstellt."

Beachten Sie, dass beim Vergleichen von Gleitkommawerten Folgendes gilt:

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 um zu testen, ob a ist NaN.

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

C99 hat auch nan Funktionen:

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

(Referenz: n1256).


71
2017-12-17 19:15



Es gibt keinen kompilerunabhängigen Weg, dies zu tun, da weder die C- noch die C ++ - Standards sagen, dass die Fließkomma-Mathe-Typen NAN oder INF unterstützen müssen.

Bearbeiten: Ich habe nur den Wortlaut des C ++ - Standards überprüft und es heißt, dass diese Funktionen (Mitglieder der Templated-Klasse numeric_limits):

quiet_NaN() 
signalling_NaN()

Möchte NAN-Repräsentationen "falls verfügbar" zurückgeben. Es geht nicht um das, was "wenn verfügbar" bedeutet, sondern vermutlich um etwas wie "wenn der FP-Vertreter der Implementierung sie unterstützt". Ebenso gibt es eine Funktion:

infinity() 

was einen positiven INF rep "wenn verfügbar" zurückgibt.

Diese sind beide definiert in der <limits> Header - Ich würde vermuten, dass der C-Standard etwas ähnliches hat (wahrscheinlich auch "wenn verfügbar"), aber ich habe keine Kopie des aktuellen C99-Standards.


33
2017-12-17 19:00



Ein kompilerunabhängiger Weg, aber kein prozessorunabhängiger Weg, diese zu bekommen:

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.


19
2017-12-17 19:08



Dies 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 schon jemand sagte, der alte IEEE-Standard sagte das Solche Werte sollten Fallen auslösen. Aber die neuen Compiler fast immer die Fallen ausschalten und zurückgeben gegebene Werte, weil Überfüllung den Fehler stört Handhabung.


18
2017-12-17 19:26



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

12
2017-08-01 13:07



<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.  */

3
2018-03-04 00:14



Ich bin auch überrascht, dass dies keine Kompilierzeitkonstanten 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. Dividieren durch 0, Log von 0, Tan von 90, das ist etwas.


0
2017-12-17 19:09