エラーが発生した場合にnanまたはinfを返すことができる数値メソッドがあります。テスト目的で、状況が正しく処理されていることを確認するために、一時的にnanまたはinfを返すように強制したいと思います。Cでnanとinfの値を作成するための、コンパイラに依存しない信頼できる方法はありますか?
約10分間グーグルした後、コンパイラに依存するソリューションしか見つけることができませんでした。
回答:
実装にそれがあるかどうかをテストできます。
#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif
の存在はINFINITY
C99(または少なくとも最新のドラフト)によって保証されており、「正または符号なしの無限大を表すfloat型の定数式に拡張されます。それ以外の場合は、変換時にオーバーフローするfloat型の正の定数に拡張されます」。
NAN
定義される場合とされない場合があり、「実装がfloat型のクワイエットNaNをサポートする場合にのみ定義されます。これは、クワイエットNaNを表すfloat型の定数式に展開されます。」
浮動小数点値を比較する場合は、次のことに注意してください。
a = NAN;
その時でさえ、
a == NAN;
は誤りです。NaNをチェックする1つの方法は、次のとおりです。
#include <math.h>
if (isnan(a)) { ... }
次のこともできます:がNaNであるa != a
かどうかをテストしa
ます。
ありisfinite()
、isinf()
、isnormal()
、およびsignbit()
マクロがでmath.h
C99インチ
C99には次のnan
機能もあります。
#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);
(参照:n1256)。
a != a
ないでください。
a
、が数値でない場合、a == NAN
falseを返す必要はありません。IEEEはそれを要求します。IEEEに準拠する実装でさえ、ほとんどの場合そうします。isnan()
実装されていない場合は、直接コーディングするよりもテストをラップする方がよいでしょうa == NAN
。
C(またはC ++)標準では、浮動小数点演算タイプがNANまたはINFをサポートする必要があるとは規定されていないため、これを行うコンパイラに依存しない方法はありません。
編集: C ++標準の文言を確認したところ、これらの関数(テンプレート化されたクラスnumeric_limitsのメンバー)は次のようになっています。
quiet_NaN()
signalling_NaN()
「利用可能な場合」、NAN表現を返します。「利用可能な場合」の意味は拡張されませんが、おそらく「実装のFP担当者がそれらをサポートしている場合」のようなものです。同様に、次の関数があります。
infinity()
これは、「利用可能な場合」に正のINF担当者を返します。
これらは両方とも<limits>
ヘッダーで定義されています-C標準には似たようなものがあると思いますが(おそらく「利用可能な場合」も)、現在のC99標準のコピーはありません。
<math.h>
定義nan()
、nanf()
およびnanl()
NaNでのそのリターン異なる表現(AS double
、float
およびint
それぞれ)、および無限(avaliable場合)を有するものを生成することによって戻すことができたlog(0)
か何か。C99でも、それらをチェックする標準的な方法はありません。<float.h>
ヘッダ(<limits.h>
整数型のためのものである)は、約残念ながら静かであるinf
とnan
値。
nanl()
返します。入力しているときに気づかなかった理由がわかりません。long double
int
これはとの両方float
で機能しdouble
ます:
double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;
編集:誰かがすでに言ったように、古いIEEE規格は、そのような値は罠を引き起こすはずだと言っていました。ただし、トラップはエラー処理に干渉するため、新しいコンパイラはほとんどの場合、トラップをオフにして指定された値を返します。
#define is_nan(x) ((x) != (x))
NANの簡単でポータブルなテストとして役立つ場合があります。
これらを取得するためのコンパイラに依存しない方法ですが、プロセッサに依存しない方法です。
int inf = 0x7F800000;
return *(float*)&inf;
int nan = 0x7F800001;
return *(float*)&nan;
これは、IEEE 754浮動小数点形式(x86が使用)を使用するすべてのプロセッサで機能するはずです。
更新:テストおよび更新されました。
(float &)
?それは私にはCのようには見えません。必要なものint i = 0x7F800000; return *(float *)&i;
0x7f800001
これは、IEEE-754標準のいわゆるシグナリングNaNであることに注意してください。ほとんどのライブラリとハードウェアはNaNのシグナリングをサポートしていませんが、のような静かなNaNを返す方がよいでしょう0x7fc00000
。
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);
strtod
、NaNとInfを必要とし、変換します。
<inf.h>
/* IEEE positive infinity. */
#if __GNUC_PREREQ(3,3)
# define INFINITY (__builtin_inff())
#else
# define INFINITY HUGE_VALF
#endif
そして
<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. */
普段使っています
#define INFINITY (1e999)
または
const double INFINITY = 1e999
これは、表現可能な最大のdouble値がおおよそであるため、少なくともIEEE754コンテキストで機能し1e308
ます。1e309
と同じように機能しますが、1e99999
スリーナインで十分で記憶に残ります。これはdoubleリテラル(この#define
場合)または実際のInf
値のいずれかであるため、128ビット(「longdouble」)浮動小数点数を使用している場合でも無限のままになります。
1e999
リテラルがに丸められなくなります+Infinity
。マーフィーの法則によれば、これはアルゴリズムを破ります。さらに悪いことに、「128ビット」ビルドを実行している人間のプログラマーは、そのエラーを事前に発見することはないでしょう。つまり、このエラーが検出されて認識されるのは遅すぎる可能性があります。とても危ない。
これらの定数を定義する簡単な方法は次のとおりです。移植性があると確信しています。
const double inf = 1.0/0.0;
const double nan = 0.0/0.0;
このコードを実行すると:
printf("inf = %f\n", inf);
printf("-inf = %f\n", -inf);
printf("nan = %f\n", nan);
printf("-nan = %f\n", -nan);
私は得る:
inf = inf
-inf = -inf
nan = -nan
-nan = nan