【问题标题】:Unusual cause of NaN in C++? Do limits approaching zero cause NaN?C ++中NaN的异常原因?接近零的极限会导致 NaN 吗?
【发布时间】:2013-07-20 14:16:05
【问题描述】:

在从事涉及神经网络的 C++ 项目时,我受到 NaN 结果的阻碍。经过大量的追踪(试图找到 NaN 的起源),我意识到它的来源是我的 sigmoid 导函数,如下所示。

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 值的来源。

【问题讨论】:

  • 感谢您快速而有帮助的回复!这是我关于 stackoverflow 的第一个问题,我印象深刻。作为编程世界的新手,我真的很感谢这么棒的在线资源

标签: c++ neural-network nan trace


【解决方案1】:

好吧,如果分子和分母最终都为 0,那么你正在做 0/0,即 NaN。

我没有计算过,但我想exp(-1008) 小于2E-308,即double 中的最小可表示值。

有人可以告诉我NaN的原因

Wikpedia has this covered.

【讨论】:

  • 其实是+inf/+inf。 exp(-(-1008)) == exp(1008)
【解决方案2】:

在每种情况下,分母都试图达到无穷大(这意味着整个分数都试图达到 0)。但是,这意味着您要在某处定义除以无穷大(结合有限的双倍范围)。

对此的解释在于 c++ exp function 如果返回值不能表示为双精度,则返回 +-HUGE_VAL。

话虽如此,当您的结果不能包含在双变量中时,它将导致 除以无穷大,从而导致 nan

顺便说一句,如果你想对大数字进行操作,你可以实现一个将数字存储在字符串和重载运算符中的类。

【讨论】:

    【解决方案3】:

    如果您的输入 n 是一个很大的负数

    exp(-n) -> inf
    
    pow(1 + exp(-n), 2) -> pow(1 + inf, 2) -> inf
    
    inf / inf -> nan
    

    如果您的输入 n 是一个很大的正数,您将永远不会得到 nan 0/0

    pow(1 + exp(-n), 2) -> pow(1 + 0, 2) != 0
    

    【讨论】:

    • yes exp(-n) -> 0,我添加了“负数”。这是获得 nan 的可能方法
    猜你喜欢
    • 1970-01-01
    • 2017-05-11
    • 2011-07-20
    • 1970-01-01
    • 2016-02-09
    • 2011-12-31
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    相关资源
    最近更新 更多