нан профилактика
Мой ответ на этот вопрос: Не используйте ретроактивные чеки для nan
. Вместо этого используйте превентивные проверки для делений вида 0.0/0.0
.
#include <float.h>
float x=0.f ; // I'm gonna divide by x!
if( !x ) // Wait! Let me check if x is 0
x = FLT_MIN ; // oh, since x was 0, i'll just make it really small instead.
float y = 0.f / x ; // whew, `nan` didn't appear.
nan
результат операции 0.f/0.f
или 0.0/0.0
. nan
- это ужасный противник стабильности вашего кода, который должен быть обнаружен и очень осторожно предотвращен 1 . Свойства nan
, отличные от обычных чисел:
nan
токсично, (5 *nan
= nan
)
nan
не равно ничему, даже самому себе (nan
! = nan
)
nan
не больше, чем что-либо (nan
!> 0)
nan
не меньше всего (nan
! <0) </li>
Последние 2 перечисленных свойства являются нелогичными и приведут к странному поведению кода, который основан на сравнении с числом nan
(3-е последнее свойство тоже странно, но вы, вероятно, никогда не увидите x != x ?
в вашем коде (если вы не проверяете nan (ненадежно))).
В своем собственном коде я заметил, что значения nan
имеют тенденцию приводить к трудностям поиска ошибок. (Обратите внимание, что не имеет место для inf
или -inf
. (-inf
<0) возвращает <code>TRUE, (0 <<code>inf) возвращает ИСТИНА и даже (-inf
<<code>inf) возвращает TRUE. По моему опыту, поведение кода часто по-прежнему соответствует желаемому.
что делать под nan
То, что вы хотите выполнить в 0.0/0.0
, должно рассматриваться как особый случай , но то, что вы делаете, должно зависеть от чисел, которые вы ожидаете получить из кода.
В приведенном выше примере, результат (0.f/FLT_MIN
) будет 0
, в основном. Вы можете захотеть, чтобы 0.0/0.0
генерировал HUGE
. Таким образом,
float x=0.f, y=0.f, z;
if( !x && !y ) // 0.f/0.f case
z = FLT_MAX ; // biggest float possible
else
z = y/x ; // regular division.
Так что в приведенном выше случае, если бы x было 0.f
, получилось бы inf
(что имеет довольно хорошее / неразрушающее поведение, как на самом деле упоминалось выше).
Помните, целочисленное деление на 0 вызывает исключение времени выполнения . Поэтому вы всегда должны проверять целочисленное деление на 0. То, что 0.0/0.0
тихо оценивается как nan
, не означает, что вы можете быть ленивым и не проверять 0.0/0.0
до того, как это произойдет.
1 Проверки для nan
через x != x
иногда ненадежны (x != x
удаляется некоторыми оптимизирующими компиляторами, которые нарушают соответствие IEEE, особенно когда включен переключатель -ffast-math
).