Математические проблемы в Java; дар NaN из расчета - PullRequest
2 голосов
/ 06 июля 2010

Я работаю над проектом, который выполняет множество запросов и некоторое математическое моделирование, основанное на результатах этих запросов, и, наконец, некоторую оценку (читай: «время выполнения слишком длинное для тщательного тестирования»).

Недавно я обнаружил довольно новую проблему / ошибку в моем коде;некоторые из результатов получают NaN значения для оценки!Вот как рассчитываются оценки:

Обратите внимание, что pfound, psig - это double с, которые всегда положительны или 0

Double  score1 = (pfound!=0) ? (Math.log(factorial((int)psig + 1))/pfound) : 0;

score1 = score1 * alpha_coeff[0];
if (score1.isInfinite())
    throw new RuntimeException(p.getName() + " score1 = Inf");
else if(score1.isNaN())
    throw new RuntimeException(p.getName() + " score1 = NaN");

Я проверил возможные причины срабатывания NaN, но я считаю, что это должно быть безопасно от большинства из них:

  1. Я уже проверяю на pfound == 0 (поэтому не делим на ноль)

  2. Аргумент Math.log () не может иметь отрицательное значение

Я подозреваю, является ли factorial() (пользовательская функция, которая возвращает факториал как long) возвращает long настолько большое, что его нельзя преобразовать в double без потери точности или чего-то в этом роде.Я проверил Long.doubleValue(), и, очевидно, он генерирует NaN, если его аргумент приводит к NaN.

Есть комментарии?Я что-то упустил здесь?

Ответы [ 3 ]

3 голосов
/ 06 июля 2010

Если ваш факториал делает наивную оценку x!= 1 * 2 * 3 ..., держу пари, что вы просите факториал числа, который не вписывается в используемую вами ссылку.

Два совета:

  1. Попробуйте BigDecimal в этом случае
  2. Используйте гамма-функцию вместо простой реализации.

Рекурсия для факториала (n), где n> 12 - очень плохая, наивная идея.Ты серьезно не думал о том, чтобы идти вперед с чем-то вроде этого?

2 голосов
/ 06 июля 2010

NaN распространяются через различные арифметические операции, поэтому, даже если вы здесь правильно проверяете условия, они могут быть введены откуда-то еще.

Я бы заподозрил либо alpha_coeff [0], либо pfound - попробуйте проверить их на наличие NaN.

NaN также может быть результатом вашей факториальной функции, в зависимости от того, как это определено. РЕДАКТИРОВАТЬ: только что заметил, что вы указали, что это производит длинный, поэтому факториал не может производить NaN, с другой стороны, он может привести к отрицательному результату, если он переполнится, что приведет к NaN из журнала ().

2 голосов
/ 06 июля 2010

Вы не должны явно сравнивать двойные значения с нулем - это почти никогда не работает.Лучше сделать что-то вроде этого:

double EPS = 0.0000001;
if (Math.abs (pfound) < EPS) { //pfound is null } 

Единственное, что я вижу, где можно получить NaN - это Math.log.Из документации:

  1. Если аргумент равен NaN или меньше нуля, то результат равен NaN.
  2. Если аргумент равен положительной бесконечности, то результат является положительнымбесконечность.
  3. Если аргумент равен положительному нулю или отрицательному нулю, то результатом является отрицательная бесконечность.

Я думаю, pfound содержит отрицательное значение или нулевой, и поэтомуВы получаете NaN.Попробуйте отследить значения переменных в отладчике.

...