отладка — сигнализация или перехват ‘nan’, как они происходят в вычислениях в базе числового кода в переполнении стека

У нас есть числовой код, написанный на C ++. Редко, но при определенных конкретных входных данных, некоторые вычисления приводят к значению ‘nan’.

Существует ли стандартный или рекомендуемый метод, с помощью которого мы можем остановить и предупредить пользователя, когда определенный численный расчет приводит к генерированию «нан»? (в режиме отладки). Проверка для каждого результата, если он равен ‘nan’, кажется непрактичной, учитывая огромные размеры матриц и векторов.

Как стандартные числовые библиотеки справляются с этой ситуацией? Не могли бы вы пролить свет на это?

4

Решение

NaN распространяется, когда применяется к числовой операции. Таким образом, достаточно проверить окончательный результат для NaN. Что касается того, как это сделать — если сборка для> = C ++ 11, есть std :: isnan, как заметил Гоз. За < C ++ 11 — если хотите быть пуленепробиваемым — я бы лично проверил битовую проверку (особенно, если это может быть связано с оптимизацией). Шаблон для NaN является

         ?  11.......1  xx.......x
sign bit ^  ^exponent^  ^fraction^

где ? может быть что угодно, и хотя бы один Икс должно быть 1.

Для решения, зависящего от платформы, есть еще одна возможность. Есть функция feenableexcept в Glibc (вероятно, с signal функция и опция компилятора -fnon-call-exceptions), который включает поколение SIGFPE sinals, когда происходит недопустимая операция с плавающей точкой. И функция _control87 (вероятно, с _set_se_translator функция и опция компилятора /EHa), что позволяет в значительной степени то же самое в VC.

1

Другие решения

Хотя это нестандартное расширение от glibc, на многих системах вы можете использовать feenableexcept рутина объявлена ​​в <fenv.h> запросить, чтобы машина перехватила определенные исключения с плавающей точкой и доставила SIGFPE к вашему процессу. Ты можешь использовать fedisableexcept маскировать ловушку, и fegetexcept запросить набор исключений, которые не маскируются. По умолчанию все они замаскированы.

На старых системах BSD без этих подпрограмм вы можете использовать fpsetmask а также fpgetmask от <ieeefp.h> вместо этого, но мир, кажется, сходится на API glibc.

Предупреждение: в настоящее время в glibc есть ошибка, из-за которой (стандартная процедура C99) fegetenv имеет непреднамеренный побочный эффект маскировки всех ловушек исключений на x86, поэтому вам нужно вызвать fesetenv чтобы восстановить их потом. (Показывает, как сильно кто-то полагается на этот материал …)

1

На многих архитектурах вы можете разоблачать недопустимое исключение, которое вызовет прерывание, когда NaN обычно генерируется вычислением, таким как 0*infinity, Запустив в отладчике, вы прерветесь на этом прерывании и сможете проверить вычисления, которые привели к этой точке. Вне отладчика вы можете установить обработчик прерываний для регистрации информации о состоянии вычислений, которые произвели недопустимую операцию.

Например, в x86 вы должны очистить бит маски недопустимой операции в FPCR (бит 0) и MXCSR (бит 7), чтобы включить перехват недопустимых операций из операций x87 и SSE соответственно.

Некоторые отдельные платформы предоставляют средства для записи в эти управляющие регистры из C, но нет переносимого интерфейса, который работает кроссплатформенно.

0

Тестирование f! = F может привести к проблемам при использовании g ++ с включенной оптимизацией -ffast-math: Проверка, является ли double (или float) NaN в C ++

Единственный надежный способ — проверить битовый паттерн.

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

-1
По вопросам рекламы [email protected]