質問
C ++でNaNを使用する最良の方法は何ですか?
std::numeric_limits<double>::quiet_NaN()
およびstd::numeric_limits<double>::signaling_NaN()
が見つかりました。次のように、初期化されていない変数を表すためにsignaling_NaN
を使用します。
double diameter = std::numeric_limits<double>::signaling_NaN();
ただし、これは割り当て時にシグナルを送信します(例外を発生させます)。割り当てではなく、使用時に例外を発生させたい。
割り当て時に例外を発生させずに<=>を使用する方法はありますか?使用すると浮動小数点例外が発生する<=>の移植性の高い代替手段はありますか?
解決
これをさらに調べてみると、signaling_NaN
は提供されているように役に立たないようです。浮動小数点例外が有効になっている場合、それを呼び出すとシグナリングNaNの処理としてカウントされるため、すぐに例外が発生します。浮動小数点例外が無効になっている場合、シグナリングNaNを処理すると、それが自動的に静かなNaNに降格されるため、<=>はどちらの方法でも機能しません。
メンクボーイのコードは機能しますが、シグナリングNaNを使用しようとすると他の問題が発生します。浮動小数点例外を有効または無効にするポータブルな方法はありません(こちらを参照) およびこちら)、例外の有効化に依存している場合、サードパーティのコードがそれらを無効にする場合があります(こちらで説明)。
だから、 Mottiのソリューションが本当に最良の選択のようです。
>他のヒント
NANのシグナル伝達とは、CPUがそれに遭遇するとシグナルが発せられることです(そのため)。初期化されていない変数を検出する場合、通常、コンパイラの警告レベルを上げると、初期化されていない値を使用するすべてのパスが検出されます。値が初期化されているかどうかを示すブール値を格納するラッパークラスを使用できない場合:
template <class T>
class initialized {
T t;
bool is_initialized;
public:
initialized() : t(T()), is_initialized(false) { }
initialized(const T& tt) : t(tt), is_initialized(true) { }
T& operator=(const T& tt) { t = tt; is_initialized = true; return t; }
operator T&() {
if (!is_initialized)
throw std::exception("uninitialized");
return t;
}
};
このような例外をトリガーすることなく、シグナルNaNを変数に書き込むことができます(nb:未テスト)
void set_snan( double &d )
{
long long *bits = (long long *)&d;
*bits = 0x7ff0000080000001LL;
}
ほとんどの場所で動作しますが、100%ポータブルではありません。
まあ、静かなNaNとシグナルNaNの両方の定義を見て、違いを実際に確認することはできません。
これらの関数で使用されているコードを自分で使用できますが、そのように例外を防ぐことができますが、これらの2つの関数で例外が表示されない場合、他の何かに関連している可能性があります。
NaNを直接割り当てる場合:
double value = _Nan._Double;
簡単な答え: ヘッダーファイルで次のようなことを行い、他のすべての場所で使用します。
#define NegativeNaN log(-1)
それらに対して何らかの操作を行いたい場合は、exp()
などのextended_exp()
の周りに拡張ラッパー関数を記述する方が良いでしょう!
C ++実装には、特定の浮動小数点例外をテストしてクリアするために、浮動小数点環境にアクセスするためのAPIが含まれている場合があります。詳細については、関連する質問への回答をご覧ください。