Когда Java может создать NaN? - PullRequest
9 голосов
/ 22 мая 2010

Я знаю, что такое Java Double.NaN.У меня есть некоторый код Java, который производит NaN.

// 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?

Ответы [ 4 ]

35 голосов
/ 22 мая 2010

NaN вызывается следующими событиями:

  • результаты, которые являются сложными значениями
    • √x, где x отрицательно
    • log (x), где x отрицательно
    • tan (x), где x mod 180 - 90
    • asin (x) или acos (x), где x находится вне [-1..1]
  • 0/0
  • ∞ / ∞
  • ∞ / -∞
  • -∞ / ∞
  • -∞ / -∞
  • 0 × ∞
  • 0 × -∞
  • 1
  • ∞ + (−∞)
  • (- ∞) + ∞

Извините за такой общий ответ, но я надеюсь, что это помогло.

4 голосов
/ 22 мая 2010

Согласно Википедии:

Существует три вида операций, которые возвращают NaN:

  • Операции с NaN как минимум одним операндом
  • неопределенные формы
    • Деления 0/0, ∞ / ∞, ∞ / −∞, −∞ / ∞ и −∞ / −∞
    • Умножения 0 × ∞ и 0 × −∞
    • Мощность 1
    • Сложения ∞ + (−∞), (−∞) + ∞ и эквивалентные вычитания.
  • Реальные операции со сложными результатами:
    • квадратный корень из отрицательного числа
    • Логарифм отрицательного числа
    • Тангенс нечетного кратного 90 градусов (или π / 2 радиан)
    • Обратный синус или косинус числа, которое меньше -1 или больше + 1.

Этот фрагмент Java-кода иллюстрирует все вышеперечисленное, кроме касательного (я подозреваю, из-за ограниченной точности 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"
    }
}

Ссылки

  • Википедия / NaN
  • JLS 15.21.1 Операторы числового равенства == и! =

    Если любой из операндов равен NaN, то результат == равен false, а результат != равен true. Действительно, тест x!=x равен true тогда и только тогда, когда значение x равно NaN. (Методы Float.isNaN и Double.isNaN также могут использоваться для проверки, является ли значение NaN.)

3 голосов
/ 22 мая 2010

Учитывая то, что я знаю о градиентном спуске, вы, скорее всего, прыгаете в бесконечность, потому что у вас нет адаптивного rate (т. Е. Ваш rate слишком большой).

0 голосов
/ 22 мая 2010

Вы пытались посыпать свой код операторами System.out.println, чтобы точно определить , где начинаются NaN?

...