エラーが発生した場合に 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 型の quiet NaN をサポートする場合にのみ定義されます。これは、quiet NaN を表す float 型の定数式に展開されます。」
浮動小数点値を比較している場合は、次のようにすることに注意してください。
a = NAN;
その時でさえ、
a == NAN;
は偽です。NaN をチェックする 1 つの方法は次のとおりです。
#include <math.h>
if (isnan(a)) { ... }
次のこともできます: NaNa != a
かどうかをテストします。a
C99 には、、、、およびisfinite()
マクロもあります。isinf()
isnormal()
signbit()
math.h
C99 には次のnan
機能もあります。
#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);
(参照:n1256)。
これを行うコンパイラに依存しない方法はありません。C (または C++) 標準のどちらも、浮動小数点演算型が NAN または INF をサポートする必要があるとは言っていないからです。
編集: C++標準の文言を確認したところ、これらの関数(テンプレート化されたクラスnumeric_limitsのメンバー)は次のようになっています。
quiet_NaN()
signalling_NaN()
「利用可能な場合」は NAN 表現を返します。「利用可能な場合」の意味を拡張するものではありませんが、おそらく「実装の FP 担当者がそれらをサポートしている場合」のようなものです。同様に、次の関数があります。
infinity()
これは、「利用可能な場合」に肯定的な INF 担当者を返します。
これらは両方とも<limits>
ヘッダーで定義されています-C標準には似たようなものがあると思います(おそらく「利用可能であれば」)が、現在のC99標準のコピーはありません。
これは、 と の両方float
で機能しdouble
ます。
double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;
編集: 誰かがすでに言ったように、古い IEEE 標準では、そのような値はトラップを発生させるべきだと述べていました。しかし、新しいコンパイラはほとんどの場合、トラップをオフにして、指定された値を返します。これは、トラップがエラー処理に干渉するためです。
これらを取得するためのコンパイラに依存しない方法ですが、プロセッサに依存しない方法は次のとおりです。
int inf = 0x7F800000;
return *(float*)&inf;
int nan = 0x7F800001;
return *(float*)&nan;
これは、IEEE 754 浮動小数点形式 (x86 で使用) を使用するすべてのプロセッサで動作するはずです。
更新: テストおよび更新されました。
<inf.h>
/* IEEE positive infinity. */
#if __GNUC_PREREQ(3,3)
# define INFINITY (__builtin_inff())
#else
# define INFINITY HUGE_VALF
#endif
and
<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
これは少なくとも IEEE 754 コンテキストで機能します1e308
。1e309
と同じように機能しますが1e99999
、スリーナインで十分で記憶に残ります。これは double リテラル (この#define
場合) または実際のInf
値のいずれかであるため、128 ビット (「long double」) 浮動小数点数を使用している場合でも、無限のままです。
これらがコンパイル時の定数ではないことにも驚いています。しかし、このような無効な結果を返す命令を実行するだけで、これらの値を簡単に作成できると思います。0 で割ると、0 の対数、90 の tan、そのようなもの。
これらの定数を定義する簡単な方法を次に示します。これは移植可能であると確信しています。
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