3

ニューラル ネットワークを含む C++ プロジェクトに取り組んでいるときに、NaN の結果に悩まされました。大量のトレース (NaN の起源を見つけようとしている) の後、そのソースが以下に示すシグモイド微分関数であることに気付きました。

double sigDer(double n){
    return 2*exp(-n) / pow(1 + exp(-n), 2);
}

すべて実数の定義域を持っていますが、-1008.3 などの値は NaN の結果を引き起こしました。Mathematica によると、正しい結果は 2.522*10^-438 のようにゼロに非常に近いはずです。次の方法で問題を回避しました。

double sigDer(double n){
    double res = 2*exp(-n) / pow(1 + exp(-n), 2);
    if( isnan(res) ){
        return 0;
    } else{
        return res;
    }
} 

この単純な仮定で、私のコードは期待どおりに機能します。ただし、なぜ sigDer(<# 大きいマグニチュード>) が ~0 を返さないのか、まだわかりません。C++ (Xcode IDE) の NaN の原因について、ゼロ除算と負の偶数根を取る以外に誰か教えてください。

前もって感謝します!また、signer(-1008.3) が NaN を返す理由と、NaN 値のソースをより適切に/より効率的にトレースする方法も知りたいです。

4

3 に答える 3

2

ライム

すべての場合において、分母は無限大に到達しようとしています (つまり、分数全体が 0 に到達しようとしています)。ただし、これは、無限大による除算をどこかに定義していることを意味します (制限された倍精度範囲と組み合わせて)。

これに関する説明は、戻り値を double として表すことができない場合に +-HUGE_VAL を返すc++ の exp 関数にあります。

そうは言っても、結果をdouble変数に含めることができない場合、無限大で除算されるため、nanになります

ところで、大きな数値を操作したい場合は、文字列やオーバーロード演算子などに数値を格納するクラスを実装できます。

于 2013-07-22T00:01:12.877 に答える