webentwicklung-frage-antwort-db.com.de

Wie verwende ich nan und inf in C?

Ich habe eine numerische Methode, die bei einem Fehler nan oder inf zurückgeben könnte, 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 einen zuverlässigen, compilerunabhängigen Weg, um Werte von nan und inf in C zu erstellen?

Nach ca. 10 Minuten googeln konnte ich nur Compiler-abhängige Lösungen finden.

78
Graphics Noob

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

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

Das Vorhandensein von INFINITY wird durch C99 (oder zumindest den letzten Entwurf) garantiert und "erweitert sich zu einem konstanten Ausdruck des Typs Float, der positiv oder vorzeichenlos ist Unendlich", falls vorhanden; Übersetzungszeit. "

NAN kann definiert werden oder nicht, und "wird genau dann definiert, wenn die Implementierung ruhige NaNs für den Float-Typ unterstützt. Er erweitert sich zu einem konstanten Ausdruck des Typs Float, der eine ruhige NaN darstellt."

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

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 NaN ist.

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(const char *tagp);

(Referenz: n1256).

Docs INFINITYDocs NAN

75
Alok Singhal

Es gibt keine vom Compiler unabhängige Möglichkeit, dies zu tun, da weder der C- (noch der C++) -Standard sagt, dass die mathematischen Gleitkommatypen NAN oder INF unterstützen müssen.

Edit: Ich habe gerade den Wortlaut des C++ - Standards überprüft und besagt, dass diese Funktionen (Mitglieder der Klasse mit der Vorlage numeric_limits):

quiet_NaN() 
signalling_NaN()

nAN-Darstellungen werden zurückgegeben, sofern verfügbar. Es wird nicht darauf eingegangen, was "wenn verfügbar" bedeutet, sondern vermutlich etwas wie "wenn die Implementierung FP rep sie unterstützt". Ebenso gibt es eine Funktion:

infinity() 

was eine positive INF Wiederholung "falls verfügbar" zurückgibt.

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

34
anon

Dies funktioniert sowohl für float als auch für double:

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

Edit: Wie schon jemand gesagt hat, 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, da das Trapping die Fehlerhandhabung stört.

20
Thorsten S.

Ein vom Compiler unabhängiger Weg, aber nicht vom Prozessor unabhä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 Fließkommaformat IEEE 754 verwendet (was x86 ist).

UPDATE: Getestet und aktualisiert.

19
Aaron
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
12
J.Kraftcheck
<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
4pie0

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 1e308 ist. 1e309 würde genauso gut funktionieren wie 1e99999, aber drei Neunen sind ausreichend und einprägsam. Da es sich hierbei entweder um ein Doppelliteral (im Fall #define) oder um einen tatsächlichen Inf-Wert handelt, bleibt es auch dann unendlich, wenn Sie 128-Bit ("long double") Floats verwenden.

0
Douglas Bagnall

Ich bin auch überrascht, dass dies keine Konstanten für die Kompilierung sind. Ich denke jedoch, Sie könnten diese Werte leicht genug erstellen, indem Sie einfach eine Anweisung ausführen, die ein solches ungültiges Ergebnis zurückgibt. Durch 0 teilen, log von 0, tan von 90, so etwas.

0
Carl Smotricz