Работая над проектом 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. Может кто-нибудь сообщить мне о причинах NaN в C ++ (Xcode IDE), кроме деления на ноль и получения четного корня отрицательного числа?
Заранее спасибо! Я также хотел бы знать, почему подписывающее лицо (-1008.3) возвращает NaN и как лучше / более эффективно отслеживать источник значений NaN.
Знаменатель в каждом случае пытается достичь бесконечности (что означает, что целая дробь пытается достичь 0). Это, однако, означает, что вы определяете где-то деление на бесконечность (в сочетании с ограниченным двойным диапазоном).
Объяснение этому заключается в функция C ++ Exp который возвращает + -HUGE_VAL, если возвращаемое значение не может быть представлено как double.
Сказав, что, когда ваш результат не может содержаться в двойной переменной, это приведет к деление на бесконечность и, таким образом, бабушка
Кстати, если вы хотите работать с большими числами, вы можете реализовать класс, который хранит числа, например, в строке и операторах перегрузки.
Что ж, если числитель и знаменатель в конечном итоге равны 0, то вы делаете 0/0, то есть NaN.
Я не сделал расчет, но я представляю exp(-1008)
меньше чем 2E-308
т.е. наименьшее представимое значение в double
,
Может кто-нибудь, пожалуйста, сообщите мне о причинах NaN
Если ваш вклад n
большой отрицательный число
exp(-n) -> inf
pow(1 + exp(-n), 2) -> pow(1 + inf, 2) -> inf
inf / inf -> nan
Если ваш вклад n
большой положительный номер, который вы никогда не получите нан 0/0
pow(1 + exp(-n), 2) -> pow(1 + 0, 2) != 0