Исключения с плавающей запятой в LINUX — как преобразовать их во что-то полезное

У меня есть кусок кода, вычисляющий вектор функций вектора независимых переменных (и параметров):

struct instance
{    double m_adParam1, m_adParam2;
     std::array<double, OUTSIZE> calculate(const std::array<double, INSIZE>&x) const;
};

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

Это также должно применяться к расчетным значениям, используемым только для сравнения. Поэтому проверки результирующего вектора на NAN или бесконечность недостаточно. Вставка тестов после каждой ошибочной операции невозможна.

Как можно это сделать?

Я читал о festestexcept(). Но непонятно, что сбрасывает этот государственный флаг. SIGFPE бесполезен ни для чего, кроме отладки. Было бы здорово иметь возможность преобразовать это в исключения C++, как в Windows, но также было бы достаточно вставить окончательную проверку.

Вставка кода для проверки недопустимых входных данных для следующего кода также невозможна, так как это значительно замедлит вычисления.

Разве вы не должны проверять перед любой из этих операций, удовлетворяются ли ограничения домена и в конечном итоге сигнализировать об ошибке?

Bob__ 10.02.2023 20:43
SIGFPE не исключение. Это часть ОС. Исключения C++ являются частью языка.
273K 10.02.2023 20:44

Несмотря на то, что они имеют одно и то же имя, исключения ОС и исключения C++ — это две совершенно разные вещи.

Pete Becker 10.02.2023 20:49

Вы можете создать свой собственный класс safe_double, который обертывает double и будет вызывать исключение, если в операции выполняется условие ошибки. Тем не менее, это делает каждую из операций проверенной, что может быть даже хуже, чем проверка правильности домена ввода.

NathanOliver 10.02.2023 20:52

@ 273K: SIGFPE — это сигнал ОС, доставляемый в ответ на аппаратное исключение, если вы демаскируете исключения с плавающей запятой. По умолчанию все исключения FP маскируются, поэтому они просто записываются в MXCSR (что и проверяет fetestexcept). В любом случае, если ваш код демаскирует исключения FP, а затем запускает одно из них, вы получаете SIGFPE. Нет ничего неправильного в том, чтобы назвать это исключением, и этот вопрос действительно спрашивает о преобразовании его в исключение C++, правильно проводя различие между исключениями HW FP и исключениями C++. (IDK, насколько возможно было бы написать обработчик SIGFPE, который выбрасывает родительский поток)

Peter Cordes 10.02.2023 22:07

Предполагая, что вы используете glibc, делает ли feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW ); то, что вы хотите?

chtz 11.02.2023 01:01

@Frank Puck Учитывая, что «когда какая-либо часть этого кода дает сбой из-за деления на (почти) ноль ... весь код должен дать сбой», почему деление почти на ноль (а не на ноль) должно завершиться ошибкой? Что не так с коэффициентом +/- бесконечности?

chux - Reinstate Monica 11.02.2023 06:18

Что касается выбрасывания изнутри обработчика сигнала, см. stackoverflow.com/questions/1717991/…. Есть примечание, что MSVC++ поддерживает его, и что gcc с -fnon-calll-exceptions может работать на некоторых платформах. Я не проверял.

Nate Eldredge 12.02.2023 19:10

В C наиболее переносимым подходом является setjmp/longjmp, но он плохо взаимодействует с C++, так как не раскручивает стек; если вы longjmp выходите за рамки некоторых объектов, их деструкторы вызываться не будут. Это может сработать, если вы держите setjmp достаточно близко к коду расчета, чтобы между ними не создавались (нетривиально) никакие объекты, и тогда вы могли бы throw, когда setjmp возвращается во второй раз.

Nate Eldredge 12.02.2023 19:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
90
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я читал о festestexcept(). Но непонятно, что сбрасывает этот государственный флаг.

Это то, что делает feclearexcept(). Итак, вы можете сделать что-то вроде

std::feclearexcept(FE_INVALID | FE_OVERFLOW | FE_DIVBYZERO);

// do lots of calculations

// now check for exceptions
if (std::fetestexcept(FE_INVALID))
    throw std::domain_error("argh");
else if (std::fetestexcept(FE_OVERFLOW))
    throw std::overflow_error("eek");
// ...

Флаги исключений являются «липкими», и никакая другая операция, кроме явного feclearexcept(), не должна их очищать.

Основные преимущества использования feenablexcept() для форсирования SIGFPE заключаются в том, что вы сразу обнаружите ошибку, не дожидаясь, пока вам не удастся проверить флаг исключения, и что вы сможете точно определить инструкцию, вызвавшую исключение. Похоже, что ни один из них не нужен в вашем случае использования.

Другие вопросы по теме