Pertanyaan Bagaimana cara menggunakan nan dan inf dalam C?


Saya memiliki metode numerik yang dapat mengembalikan nan atau inf jika ada kesalahan, dan untuk tujuan pengujian saya ingin memaksa sementara untuk mengembalikan nan atau inf untuk memastikan situasi sedang ditangani dengan benar. Apakah ada yang bisa diandalkan, compiler-independent cara untuk menciptakan nilai-nilai nan dan inf dalam C?

Setelah googling selama 10 menit, saya hanya dapat menemukan solusi yang bergantung pada compiler.


76
2017-12-17 18:57


asal


Jawaban:


Anda dapat menguji apakah penerapan Anda memilikinya:

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

Keberadaan INFINITY dijamin oleh C99 (atau draft terbaru setidaknya), dan "diperluas ke ekspresi konstan tipe float yang mewakili positif atau unsigned tak terbatas, jika tersedia; lain untuk konstanta positif tipe float yang meluap pada waktu terjemahan. "

NAN mungkin atau mungkin tidak didefinisikan, dan "ditentukan jika dan hanya jika implementasi mendukung NaNs yang tenang untuk tipe float. Ini meluas ke ekspresi konstan tipe float yang mewakili NaN yang tenang."

Perhatikan bahwa jika Anda membandingkan nilai titik mengambang, dan lakukan:

a = NAN;

bahkan kemudian,

a == NAN;

salah. Salah satu cara untuk memeriksa NaN adalah:

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

Anda juga bisa melakukan: a != a untuk menguji apakah a adalah NaN.

Ada juga isfinite(), isinf(), isnormal(), dan signbit() macro dalam math.h di C99.

C99 juga punya nan fungsi:

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

(Referensi: n1256).


71
2017-12-17 19:15



Tidak ada cara independen compiler untuk melakukan ini, karena baik C (maupun C ++) standar mengatakan bahwa jenis matematika floating point harus mendukung NAN atau INF.

Edit: Saya hanya memeriksa susunan kata dari standar C ++, dan mengatakan bahwa fungsi-fungsi ini (anggota dari class numeric_limits templated):

quiet_NaN() 
signalling_NaN()

wiill mengembalikan representasi NAN "jika tersedia". Itu tidak memperluas apa "jika tersedia" berarti, tapi mungkin sesuatu seperti "jika perwakilan FP implementasi mendukung mereka". Demikian pula, ada fungsi:

infinity() 

yang mengembalikan rep INF positif "jika tersedia".

Keduanya didefinisikan dalam <limits> header - Saya menduga bahwa standar C memiliki sesuatu yang serupa (mungkin juga "jika tersedia") tetapi saya tidak memiliki salinan standar C99 saat ini.


33
2017-12-17 19:00



Cara independen compiler, tetapi bukan cara independen prosesor untuk mendapatkan ini:

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

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

Ini harus bekerja pada prosesor apa pun yang menggunakan format floating point IEEE 754 (yang x86 lakukan).

UPDATE: Diuji dan diperbarui.


19
2017-12-17 19:08



Ini berfungsi untuk keduanya float dan double:

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

Edit: Seperti yang sudah dikatakan seseorang, standar lama IEEE mengatakan itu nilai-nilai tersebut harus meningkatkan jebakan. Tetapi kompiler baru hampir selalu mengganti perangkap dan mengembalikan nilai yang diberikan karena menjebak mengganggu kesalahan penanganan.


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

dan

<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



Saya juga terkejut ini tidak mengkompilasi konstanta waktu. Tapi saya kira Anda dapat membuat nilai-nilai ini cukup mudah dengan hanya mengeksekusi instruksi yang mengembalikan hasil yang tidak valid tersebut. Membagi dengan 0, log 0, tan 90, itu agak.


0
2017-12-17 19:09



Saya biasanya menggunakan

#define INFINITY (1e999)

atau

const double INFINITY = 1e999

yang bekerja paling tidak dalam konteks IEEE 754 karena nilai ganda tertinggi yang dapat mewakili secara kasar 1e308. 1e309 akan bekerja dengan baik, juga 1e99999, tetapi tiga sembilan cukup dan mudah diingat. Karena ini adalah literal ganda (dalam #define case) atau sebenarnya Inf nilai, itu akan tetap tak terbatas bahkan jika Anda menggunakan pelampung 128-bit ("panjang ganda").


0
2017-07-15 22:58