【问题标题】:When can Java produce a NaN?Java 什么时候可以产生 NaN?
【发布时间】:2011-02-22 15:32:56
【问题描述】:

我知道 Java Double.NaN 是什么。我有一些生成NaN 的Java 代码。

// calculate errors
delta = m1 + m2 - M;
eta = f1 + f2 - F;
for (int i = 0; i < numChildren; i++) {
  epsilon[i] = p[i]*m1+(1-p[i])*m2+q[i]*f1+(1-q[i])*f2-C[i];
}

// use errors in gradient descent
// set aside differences for the p's and q's
float mDiff = m1 - m2;
float fDiff = f1 - f2;
// first update m's and f's
m1 -= rate*delta;
m2 -= rate*delta;
f1 -= rate*eta;
f2 -= rate*eta;
for (int i = 0; i < numChildren; i++) {
  m1 -= rate*epsilon[i]*p[i];
  m2 -= rate*epsilon[i]*(1-p[i]);
  f1 -= rate*epsilon[i]*q[i];
  f2 -= rate*epsilon[i]*(1-q[i]);
}
// now update the p's and q's
for (int i = 0; i < numChildren; i++) {
  p[i] -= rate*epsilon[i]*mDiff;
  q[i] -= rate*epsilon[i]*fDiff;  
}

Java 在什么情况下会产生 NaN 值?

【问题讨论】:

    标签: java nan


    【解决方案1】:

    NaN 由以下事件触发:

    • 复数值的结果
      • √x 其中 x 为负数
      • log(x) 其中 x 为负数
      • tan(x) 其中 x mod 180 为 90
      • asin(x) 或 acos(x),其中 x 在 [-1..1] 之外
    • 0/0
    • ∞/∞
    • ∞/−∞
    • −∞/∞
    • -∞/-∞
    • 0×∞
    • 0×−∞
    • 1
    • ∞ + (−∞)
    • (−∞) + ∞

    很抱歉这么笼统的回答,但我希望对您有所帮助。

    【讨论】:

    • 嗯,从这个列表中我可以清楚地推断出它一定是涉及加法或乘法的其中之一,所以我想它归结为寻找溢出的地方。
    • 对于像我一样好奇的人,为什么会有 1^∞:mathforum.org/library/drmath/view/56006.html
    【解决方案2】:

    根据维基百科:

    返回NaN的操作有3种:

    • NaN 作为至少一个操作数的操作
    • 不确定的形式
      • 0/0、∞/∞、∞/-∞、-∞/∞和-∞/-∞等分法
      • 0×∞ 和 0×−∞ 的乘法
      • 力量1
      • 加法 ∞ + (−∞)、(−∞) + ∞ 和等效减法。
    • 具有复杂结果的实际操作:
      • 负数的平方根
      • 负数的对数
      • 90 度(或 π/2 弧度)的奇数倍的正切
      • 小于 -1 或大于 +1 的数的反正弦或余弦。

    这个 Java sn-p 说明了上述所有内容,但切线除外(我怀疑是因为 double 的精度有限):

    import java.util.*;
    import static java.lang.Double.NaN;
    import static java.lang.Double.POSITIVE_INFINITY;
    import static java.lang.Double.NEGATIVE_INFINITY;
    
    public class NaN {
        public static void main(String args[]) {
            double[] allNaNs = {
                0D/0D,
                POSITIVE_INFINITY / POSITIVE_INFINITY,
                POSITIVE_INFINITY / NEGATIVE_INFINITY,
                NEGATIVE_INFINITY / POSITIVE_INFINITY,
                NEGATIVE_INFINITY / NEGATIVE_INFINITY,
                0 * POSITIVE_INFINITY,
                0 * NEGATIVE_INFINITY,
                Math.pow(1, POSITIVE_INFINITY),
                POSITIVE_INFINITY + NEGATIVE_INFINITY,
                NEGATIVE_INFINITY + POSITIVE_INFINITY,
                POSITIVE_INFINITY - POSITIVE_INFINITY,
                NEGATIVE_INFINITY - NEGATIVE_INFINITY,
                Math.sqrt(-1),
                Math.log(-1),
                Math.asin(-2),
                Math.acos(+2),
            };
            System.out.println(Arrays.toString(allNaNs));
            // prints "[NaN, NaN...]"
            System.out.println(NaN == NaN); // prints "false"
            System.out.println(Double.isNaN(NaN)); // prints "true"
        }
    }
    

    参考文献

    【讨论】:

      【解决方案3】:

      根据我对梯度下降的了解,您很可能会跳到无穷大,因为您没有自适应 rate(即您的 rate 太大)。

      【讨论】:

      • 你是完全正确的。我调整了利率,现在它表现得很好——让我很尴尬地没有先想到明显的事情。
      【解决方案4】:

      您是否尝试过在代码中添加System.out.println 语句来确定准确 NaN 开始出现的位置?

      【讨论】:

      • 我做了很多,但不是全部。我现在已经做了所有事情,似乎渐变可以将所有内容推到无穷大,所以我可能不得不添加一些临时方法来推回它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-24
      • 1970-01-01
      • 2010-12-23
      • 1970-01-01
      • 1970-01-01
      • 2015-11-20
      • 1970-01-01
      相关资源
      最近更新 更多