質問

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が含まれている場合があります。詳細については、関連する質問への回答をご覧ください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top