Как отключить исключения с плавающей запятой в коде C/C++?

В моем коде C или C++ я хочу, чтобы деление на 0 приводило к значению с плавающей запятой +Infinity или -Infinity, вызывая sqrt(-1) или log(0) для получения значения с плавающей запятой NaN и т. д. в соответствии со спецификацией IEE754. Текущее поведение, которое я наблюдаю, когда происходит что-либо из этого, представляет собой исключение с плавающей запятой. Перехват исключений выходит за рамки моей программы, поскольку она выполняет большое количество операций, а затем выполняет агрегатную функцию, поэтому, если даже один NaN или бесконечность, она должна «отравить» результаты и сделать его бесконечностью или бесконечностью. не-число.

Я упоминаю C и C++, потому что существует некоторая совместимость, например. функция C, скомпилированная в общую библиотеку объектов, которая может выполнять операцию с плавающей запятой, но вызывается из C++.

Первоначально я смог написать некоторый код на C, и казалось, что по умолчанию НЕ выбрасывалось исключение. Однако это был одноразовый код для проверки поведения, и, к сожалению, я его не сохранил. Теперь, когда я пытаюсь это сделать, я не могу вернуться к тому моменту, когда я могу поместить NaN в число с плавающей запятой, а затем распечатать его, вместо этого я получаю исключение.

В С++ я использую:

#include <cfenv>

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

std::fenv_t envp;
// Clear all floating-point exceptions (not strictly necessary?)
std::feclearexcept(FE_ALL_EXCEPT);
// save floating point environment and then don't generate exceptions
std::feholdexcept(&envp);

// Disable all floating-point exceptions (just for good measure)
fedisableexcept(FE_ALL_EXCEPT);

Я компилирую это с помощью g++ со следующими флагами:

-fno-trapping-math -fno-signaling-nans

В C я использую аналогичный подход:

#include <fenv.h>
#pragma STDC FENV_ACCESS ON

int main() {
    fenv_t envp;
    printf("debug0:%d\n",feholdexcept(&envp));
    printf("debug1:%f\n",1/0);
}

примечание: я попробовал прагму в своем коде на C++, но g++ не распознал ее.

gcc -fno-trapping-math -fno-signaling-nans -o test test.c -lm

Версия gcc — 6.3, версия g++ — 6.5 (на данный момент у меня нет возможности использовать более новую версию, поскольку они работают в производственных системах.)

C не генерирует исключений (за исключением, возможно, целочисленного деления на ноль).

Weather Vane 06.09.2024 13:54

Деление IIRC на ноль не вызывает исключений. Вместо этого у вас, вероятно, произошел сбой в работе системы (SIGFPE).

Fareanor 06.09.2024 13:58

@Fareanor - это то, что я имел в виду, вам придется перехватить прерывание, на MSVC код обычно зависает.

Weather Vane 06.09.2024 13:59

@WeatherVane: Re: «C не генерирует исключений (за исключением, возможно, целочисленного деления на ноль)»: исключения C++ и исключения с плавающей запятой — это разные вещи. Стандарт C допускает исключения с плавающей запятой и позволяет их перехватывать.

Eric Postpischil 06.09.2024 14:03
1/0 не является плавающей запятой. Это целочисленная арифметика, и она не может производить бесконечность... Вы имели в виду 1.0/0?
ChrisMM 06.09.2024 14:03

@ChrisMM хороший улов... код библиотеки немного сложнее, но я думаю, что приведение к плавающему состоянию может отсутствовать в каком-то месте...

Michael 06.09.2024 14:07

Вам следует перефразировать свой вопрос. В плавающей запятой исключением является «Событие, которое происходит, когда операция над некоторыми конкретными операндами не дает результата, подходящего для любого разумного приложения» (IEEE-754 2019, пункт 2.1). Например, деление 1 на 3 создает неточное исключение. Событие здесь в том, что возникает это условие. Это не означает, что используется ловушка. Вы ничего не можете сделать, чтобы предотвратить исключение; это особенность операции. Кажется, вы хотите предотвратить ловушки; вы хотите, чтобы выполнение продолжалось без остановки или перехвата.

Eric Postpischil 06.09.2024 14:11

Деление целого числа на ноль может привести к SIGFPE, по крайней мере, в Linux, но это выходит за рамки языковых стандартов. Вы не можете подавить этот SIGFPE с помощью функций из <fenv>, и вы не можете вместо этого получить inf.

Weijun Zhou 06.09.2024 14:13
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Выражение 1/0 вызывает исключение, поскольку вы выполняете деление на ноль целых чисел. Здесь не используется тип с плавающей запятой.

Там, где в вашем реальном коде происходит деление на ноль, необходимо использовать типы с плавающей запятой, чтобы результат генерировал значение INF.

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

Michael 06.09.2024 14:08

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