float f = (float)'a';
if(f < 0){
}
else if(f == 0){
}
else if(f > 0){
}
else{
printf("NaN\n");
}
f
は、NaN
の場合、0
より大きく/等しく/小さくなりません。
しかし、そもそもそのようなf
をどのように生成するのでしょうか?
NaN
を作成するためにさまざまな方法を試しましたが、何も動作しませんでした。
浮動小数点数を使用して、0.0 / 0.0
は「ゼロ除算」エラーではありません。結果はNaN
になります。
このCプログラムは-nan
:
#include <stdio.h>
int main()
{
float x = 0.0 / 0.0;
printf("%f\n", x);
return 0;
}
コンピュータにとってNaN
がどのように見えるかに関して、2つの「無効な」数値は「シグナリング」と「静かな」NaNのために予約されています(正と負の無限大のために予約された2つの無効な数値と同様)。 Wikipediaのエントリ には、NaNがIEE浮動小数点数としてどのように表されるかについての詳細があります。
ナンを生成するには、いくつかの方法があります。
1)手動で生成します(_ieee754
_を読んで、ビットを正しく設定します)
2)マクロを使用します。 GCCはマクロNAN
を公開します。 math.hで定義されています
ナンをチェックする一般的な方法は、if (f == f)
をチェックすることです(ナンの値では失敗するはずです)。
Nanの場合、float表現の指数ビットはすべて1に設定する必要があります(floatは、符号付きビット、指数ビットのセット、および仮数ビットのセットで構成されます)。
NAN
マクロ、または単に_nan/nanf
_関数の1つを使用して、nan値を変数に割り当てることができます。
nan値を処理しているかどうかを確認するには、isnan()
を使用できます。次に例を示します。
_#include <stdio.h>
#include <math.h>
int main(void) {
float a = NAN;//using the macro in math.h
float f = nanf("");//using the function version
double d = nan("");//same as above but for doubles!
printf("a = %f\nf = %f\nd = %f\n",a,f,d);
if(isnan(a))
puts("a is a not a number!(NAN)\n");
return 0;
}
_
上記のコードスニペットを実行すると、次の出力が得られます。
_a = nan
f = nan
d = nan
a is a not a number!(NAN)
_
自分でコードを実行します。 http://ideone.com/WWZBl8
詳細情報を読む: http://www.cplusplus.com/reference/cmath/NAN/
GNU GCCマニュアルmath.h
は、変数を無限大またはNaNに明示的に設定できるマクロを定義します。これはC99の一部なので、他のc99準拠のコンパイラで次のマクロを使用できます。
—マクロ:float INFINITY正の無限大を表す式。これは、1.0/0.0のような数学演算によって生成された値と同じです。 -INFINITYは負の無限大を表します。
このマクロと比較することで、浮動小数点値が無限であるかどうかをテストできます。ただし、これはお勧めできません。代わりにisfiniteマクロを使用する必要があります。浮動小数点クラスを参照してください。
このマクロは、ISO C99標準で導入されました。
—マクロ:float NAN「数値ではない」値を表す式。このマクロはGNU拡張であり、「数値ではない」値をサポートするマシン、つまりIEEE浮動小数点をサポートするすべてのマシンでのみ使用できます。
「#ifdef NAN」を使用して、マシンがNaNをサポートしているかどうかをテストできます。 (もちろん、GNU拡張が表示されるように調整する必要があります。その後、math.hを含める必要があります。)
詳細については、こちらをご覧ください: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html
ホストされたCの実装では、#include <math.h>
を実行し、NAN
マクロを定義して使用できます。たとえば、GCCでは、組み込みの(__builtin_nanf (""))
によって実装されます。
(<math.h>
ヘッダーが使用できない場合がある)独立したC実装の場合、またはNAN
マクロが定義されていない場合(NaNがサポートされている場合でも発生する可能性があります)、次のコマンドでNaNを生成できます。 0.0 / 0.0
などの浮動小数点演算。ただし、いくつかの問題がある可能性があります。
まず、このような操作でも例外が生成され、一部のC実装ではトラップが発生する可能性があります。コンパイル時に次のように計算されることを確認できます。
static double my_nan = 0.0 / 0.0;
もう1つの問題は、Microsoft Visual C++(少なくとも一部のバージョン)が0.0 / 0.0
をコンパイル時に(この式がコード内の任意の場所にある場合でも)評価しようとし、その有効性について不平を言うことです。したがって、ここでのソリューションは反対です:コンパイラがコンパイル時にそれを評価しないことを確認してください:
static double zero = 0.0;
次にzero / zero
を使用します。これらのソリューションは競合しているため、 特定のマクロ でプリプロセッサディレクティブ(#if
...)を使用してコンパイラをテストできます。
NaNエンコーディングに基づくソリューションを選択することもできますが、移植性の問題もあります。まず、IEEE 754規格はNaNのエンコードを完全には定義していません。特に、静かなNaNとシグナリングNaNを区別する方法(ハードウェアは実際には異なります)。シグナルNaNは未定義の動作を引き起こします。さらに、IEEE 754規格は、ビットストリングがメモリ内でどのように表されるかを定義していません。つまり、エンディアンを検出する必要があるかもしれません。これらの問題が解決された場合、浮動小数点型を取得するには、ポインタキャストを含むunsigned char
の共用体または配列が適切です。 Cのエイリアシングルールに違反するため、アドレスにキャストされたポインターを整数に使用して型パンニングを行わないでください。
これは定数でも機能します(0/0はvsでコンパイラエラーになります):
const unsigned maxU = ~0;
const float qNan = *((float*)&maxU);
-nan
は、以下に示すように、float変数のすべての32ビットを1に設定することによっても生成できます。
float nan_val = 0xffffffff;
また、float変数が-nan
かどうかを明示的に比較するには、それ自体との比較が失敗したかどうかを確認します。
if (nan_val != nan_val) {
// executes iff nan_val is -nan
}
この比較方法は、IEEE floatを使用するコンパイラーで機能するはずです。
@Dan Cecile OR sqrt(-1)で述べられているように、0.0/0.0のような値がプログラムに含まれている場合、nanが生成されます。
次のCプログラムはNaNを生成します。 2番目のステートメントはNaNになります。
#include <stdio.h>
#include <tchar.h>
#include "math.h"
int _tmain(int argc, _TCHAR* argv[])
{
double dSQRTValue = sqrt( -1.00 );
double dResult = -dSQRTValue; // This statement will result in a NaN.
printf( "\n %lf", dResult );
return 0;
}
以下はプログラムの出力です。
1.#QNAN0