Контакт с Исключениями в операции с плавающей запятой

Я не уверен, как иметь дело с исключениями в операции с плавающей запятой или в C или в C++. От Wiki, там следуют за типами исключений в операции с плавающей запятой:

IEEE 754 specifies five arithmetic errors that are to be recorded in "sticky bits" (by default; note that trapping and other alternatives are optional and, if provided, non-default).  

* inexact, set if the rounded (and returned) value is different from the mathematically exact result of the operation.  
* underflow, set if the rounded value is tiny (as specified in IEEE 754) and inexact (or maybe limited to if it has denormalisation loss, as per the 1984 version of IEEE 754), returning a subnormal value (including the zeroes).  
* overflow, set if the absolute value of the rounded value is too large to be represented (an infinity or maximal finite value is returned, depending on which rounding is used).  
* divide-by-zero, set if the result is infinite given finite operands (returning an infinity, either +∞ or −∞).  
* invalid, set if a real-valued result cannot be returned (like for sqrt(−1), or 0/0), returning a quiet NaN.

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

Компилятор как gcc, который в состоянии дать предупреждение для некоторого очевидного случая?

То, что я могу сделать во время кодирования моей программы для уведомления, где ошибка происходит и что вводит его, - когда это происходит, так, чтобы я мог определить местоположение ошибки легко в моем коде? Дайте решения и в C и в случае C++.

Спасибо и наилучшие пожелания!

11
задан Tim 8 February 2010 в 02:24
поделиться

6 ответов

В Linux вы можете использовать расширение GNU feenableexcept (скрыто внизу этого page), чтобы включить перехват исключений с плавающей запятой - если вы сделаете это, вы получите сигнал SIGFPE, когда произойдет исключение, которое вы затем сможете перехватить в своем отладчике. Однако будьте осторожны, поскольку иногда сигнал с плавающей запятой выдается после той, которая на самом деле вызывает проблему, давая вводящую в заблуждение информацию о строке в отладчике!

6
ответ дан 3 December 2019 в 04:13
поделиться

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

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

См., Например ...

LIST OF FUNCTIONS

 Each of the functions that use floating-point values are provided in sin-
 gle, double, and extended precision; the double precision prototypes are
 listed here.  The man pages for the individual functions provide more
 details on their use, special cases, and prototypes for their single and
 extended precision versions.

 int fpclassify(double)
 int isfinite(double)
 int isinf(double)
 int isnan(double)
 int isnormal(double)
 int signbit(double)

Обновление: Всем, кто действительно думает, что в наши дни операции FPU генерируют SIGFPE по умолчанию, я рекомендую вам попробовать эту программу. Вы можете легко создать недополнение, переполнение и деление на ноль. То, что вы не будете генерировать (если вы не запустите его на последнем выжившем VAX или на RISC, отличном от 754), так это SIGFPE:

#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av) { return printf("%f\n", atof(av[1]) / atof(av[2])); }
12
ответ дан 3 December 2019 в 04:13
поделиться

В Windows с Visual C++ вы можете контролировать, какие исключения с плавающей точкой будут сняты с маски, используя _control87() и т.д. . Незамаскированные исключения с плавающей точкой генерируют структурированные исключения, которые можно обработать с помощью __try/__except (и нескольких других механизмов). Все это полностью зависит от платформы.

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

Разве все это лучше, чем предложение DigitalRoss о проверке результата? В большинстве случаев - нет. Если вам нужно обнаружить (или контролировать) округление (что маловероятно), тогда возможно.

В Windows с Borland/CodeGear/Embarcadero C++ некоторые исключения с плавающей точкой по умолчанию не маскируются, что часто вызывает проблемы при использовании сторонних библиотек, которые не тестировались с не маскированными исключениями с плавающей точкой.

4
ответ дан 3 December 2019 в 04:13
поделиться

В C99 введены функции для обработки исключений с плавающей запятой. Перед операцией с плавающей запятой вы можете использовать feclearexcept () для очистки любых невыполненных исключений. После выполнения операции (операций) вы можете использовать fetestexcept () , чтобы проверить, какие флаги исключения установлены.

1
ответ дан 3 December 2019 в 04:13
поделиться

Разные компиляторы обрабатывают эти ошибки по-разному.

Неточность почти всегда является результатом деления чисел с абсолютным значением больше единицы (возможно, через трансендентальные функции). Сложение, вычитание и умножение чисел с абсолютным значением> 1.0 может привести только к переполнению.

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

Переполнение - это проблема, которая обычно может быть обнаружена каким-то «бесконечным» сравнением, разные компиляторы различаются.

Деление на ноль весьма заметно, поскольку ваша программа (должна) вылететь, если у вас нет обработчика ошибок. Проверка дивидендов и делителей поможет избежать проблемы.

Неверные ответы обычно выявляются без специальных обработчиков ошибок с выводом какой-либо ошибки DOMAIN.

[РЕДАКТИРОВАТЬ]

Это может помочь: (Руководство по численным вычислениям от Sun) http://docs.sun.com / source / 806-3568 /

2
ответ дан 3 December 2019 в 04:13
поделиться

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

0
ответ дан 3 December 2019 в 04:13
поделиться